Break

Building a Real-time Chatter Feed Dashboard with Rails 4

Chatter is an enterprise social network and collaboration environment. Force.com exposes various useful information from Chatter such as users, organizations, groups, feed-items through APIs. Using this information, we can build a proof-of-concept dashboard which will show a user’s or organization’s feed in real-time. Real-time dashboard can provide an accurate understanding of what is happening in an organization.

This tutorial expects that you are an intermediate-level web application developer and have a few weeks of experience with Rails and related ecology. This means you should be familiar with building blocks of a Rails app and terms like OAuth, REST, Callback, bundler, gem etc.

Here is an outline of how things will work:

User can login to our Rails4 powered dashboard (a connected app) using ‘Sign in with Salesforce’ (Oauth 2). We use OAuth to get a secret token for each user from salesforce.com. We can use the token to call APIs.

Our goal is to receive a callback to server whenever anything is posted on Chatter. Unfortunately, Force.com doesn’t support a PushTopic for FeedItem, so we will use a work-around to trigger a callback whenever a FeedItem is created. First, we will create a trigger on FeedItem, this trigger will create a custom object named ProxyFeedItem, which will copy necessary fields like body, time, parent_id etc. from the FeedItem.

ProxyFeedItem will be created whenever there’s an update to any FeedItem. This will send a callback to the server with data of the ProxyFeedItem.

We will need to forward this incoming data to user’s browser. We will set up another faye channel and just transfer the data we received in step 4.

First, go to https://developer.salesforce.com/signup and register for your free Developer Edition (DE) account. For the purposes of this example, I recommend sign up for a Developer Edition even if you already have an account. This ensures you get a clean environment with the latest features enabled. After sign up, make a connected app by following the directions found in this article from the salesforce.com developer portal. Use http://localhost:3000 as Start URL, enable Oauth settings, select appropriate permissions and use http://localhost:3000/oauth/salesforce/callback as callback URL. When you create your app, you will get the app’s Consumer Key and Consumer Secret.

We have set up everything that we need from Force.com for this section and we can move on to our web application code. Create a new Rails4 application with

rails new chatter-dashboard

This will go ahead and create a Rails4 project with the name ‘chatter-dashboard’ and install the dependencies mentioned in Gemfile. Actually, we need a few more dependencies. Change Gemfile to the following:

Run bundle install, which will install additional dependencies. To start our server, run rails s puma; this will run rails with a puma server and you should be able to see a welcome page on http://localhost:3000.

The next step is to set up Oauth with salesforce.com. Add Consumer Key and Consumer Secret to chatter-dashboard/config/secrets.yml

development:
secret_key_base:
salesforce_key:
salesforce_secret:

test:
secret_key_base:

# Do not keep production secrets in the repository,
# instead read values from the environment.
production:
secret_key_base:

Create a chatter-dashboard/config/initializers/omniauth.rb file and add the following code into it:

This configures our omniauth and omniauth-salesforce gems. It has basically added a middleware in our Rails application, which will handle Oauth for us. You can read the documentation for these gems to dig deeper.

Now, run the following commands to set up two controllers and relevant routes; one for the login page and the other for the feed page:

rails g controller Login login
rails g controller Feed feed

Now, in the chatter-dashboard/config/routes.rb file, add the following routes:

This will basically add a callback route to which the user will be redirected to by Force.com after the Oauth procedure has finished successfully. We have also added a root route, so that whenever we go to http://localhost:3000, it will trigger the login#login route. Currently, it’s just an empty page. Let’s add a ‘Sign in with Salesforce’ link to it. Add the following line to chatter-dashboard/app/views/login/login.html.erb:

If you hit refresh and click on ‘Sign in with Salesforce’, you will be taken to the login page of salesforce.com if you are not signed in. After signing in and giving the app permissions, you will be redirected to http://localhost:3000/auth/salesforce/callback, but we haven’t implemented matching sessions#create yet. Let’s do that by doing rails g controller Sessions create. For the implementing create method, use the following code:

Here, we parse the callback request coming from Force.com and get oauth_token, refresh_token etc and create a restforce client. If you see something like the following in your console, then you have completed the first section of this tutorial:

In the first section of the tutorial, we set up Oauth with salesforce.com and created a restforce client object. In this section, we want Force.com to notify us of any changes in the FeedItem object of Chatter. Unfortunately, Salesforce streaming API doesn’t support FeedItem yet, so we will have to do a work-around.

Whenever ChatterListenEM.start is called, it creates a PushTopic named ChatterFeedItem, if it doesn’t already exist. Next, it creates a new thread and subscribes to that PushTopic in it. Whenever we receive a message, we pass it a Faye channel e.g. messages/new using private_pub. private_pub is a ruby gem, which makes it easier to setup a pub-sub type mechanism between a web server and browser. You can learn more about it in this screencast on private pub

Before going to private_pub and related stuff, let’s call our ChatterListenEM.start method from SessionController. There is just one minor change:

Now, let’s set up private_pub. Run rails g private_pub:install on console. It will create and place necessary files like private_pub.ru, private_pub.yml and faye.js, private_pub.js in asset-pipeline. To make rails aware of faye.js and private_pub.js files, add them to the chatter-dashboard/app/assets/javascripts/application.js file.

// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file.
//
// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require jquery
//= require jquery_ujs
//= require faye
//= require private_pub
//= require turbolinks
//= require_tree .

Start our Faye server in a different console. This will handle pub-sub for us.

rackup private_pub.ru -s thin -E production

All that is left to do now is to subscribe to the channel /messages/new and print our data. We can take easy examples from the private_pub documentation and add the following to our chatter-dashboard/app/views/feed/feed.html.erb:

and the following to our chatter-dashboard/assets/javascripts/feed.js:

Now, go to http://localhost:3000, ‘Login with Salesforce’ and you will end up on the feed page. Open the developer console and in another tab open the Chatter tab of salesforce.com. If you do a text post, you will be able to see a real time update in the console.

Here’s a proof of concept, showing the dashboard in action:

We just implemented a system like below:

Instead of printing data in console, you can easily feed it into any frontend framework like angular, ember etc. and create a great real-time dashboard.

We also have left out few things in this proof-of-concept prototype e.g. we have to secure our faye channels. One way of doing this is creating a different channel for each user. e.g. /messages/new/user_id and subscribe the user only to that particular channel. Additionally, use SSL. If you are handling any real user data, it is important that you secure the data being transferred. Force.com makes sure to secure the data and only provides developers with data over SSL using OAuth. It is however the responsibility of the developer to ensure secure communication in any RESTful app. For more information, you should refer to Security Resources.