Build a realtime chat widget using Ruby


This tutorial assumes that you have signed up for Pusher already, and have your API keys available.

We will cover the following:

  • Adding the PusherChatWidget JavaScript library and CSS to your HTML view
  • Integrating the example backend code with your existing server

First things first

If you have a github account and are happy using git you can fork or clone the project from github (or download a zip instead).

Once you have the code you should make it accessible on your chosen web server hosting. For the purposes of getting up and running we’ll assume that the code is in a directory named pusher-realtime-chat-widget in the root of your app.

You will also need to create a free Pusher account.

Add the dependencies

For the frontend we’ll need to include a few JavaScript libraries; the Pusher JavaScript library, jQuery, and the PusherChatWidget JavaScript library and stylesheet:

1<script src="//"></script>
2<script src="//<%= APP_CONFIG[:demo_js_version] %>/pusher.min.js"></script>
4<!-- Downloaded in step 1 -->
5<script src="pusher-realtime-chat-widget/src/js/PusherChatWidget.js"></script>
6<link href="pusher-realtime-chat-widget/src/pusher-chat.css" rel="stylesheet" />

For the backend use the appropriate package management solution:

1# Within `src/ruby` run the `bundle install` command
2bundle install

Initialize Pusher Chat Widget

Now the libraries are included we need to connect to Pusher and create a PusherChatWidget instance, passing in the pusher instance, which will then subscribe to a chat channel based on the URL of the current page and create the chat widget in the UI. This can be done in just a few lines of code. The only change you’ll need to make is to replace YOUR_APP_KEY with your own app_key.

1$(function() {     
2  var pusher = new Pusher('YOUR_APP_KEY');
3  var chatWidget = new PusherChatWidget(pusher, {
4    chatEndPoint: 'pusher-realtime-chat-widget/src/php/chat.php'
5  });

In the example above you’ll see that we’ve also passed in a second options parameter to the PusherChatWidget constructor. This is so the widget knows where to make the AJAX requests to in order for the server to validate and then trigger chat messages. The value of chatEndPoint should be updated so that the following file is executed (depending on your server technology):

Ruby - pusher-realtime-chat-widget/src/ruby-sinatra/chat.rb

Create & update your config

Within the sample application you’ll find example configuration files.

1# Rename `config_example.rb` to `config.rb` and update to use your own Pusher application credentials.
2# config.rb    
3require 'pusher'
5Pusher.app_id = 'YOUR_APP_KEY'
6Pusher.key = 'YOUR_APP_SECRET'
7Pusher.secret = 'YOUR_APP_ID'

Where next?

Now you’ve got your Pusher-Powered Realtime Chat widget up and running it’s time to consider how you can make this widget work with your site or application; how can you integrate it with your app and what features can you add to make it much more exciting, usable and valuable? Here are a few ideas:

Personalise by integrating with your existing user accounts

In the example widget we’re using Gravatar to personalise the chat. If a user supplies the optional email address we can use it to look up their Gravatar (Avatar) and display it along with their chosen nickname when they send a chat message. However, many applications already have user accounts so rather than using Gravatar it would be great to use the existing user account information.

For the moment the widget only supports a displayName and and image and you can use your own by passing them into the Activity object constructor:

1options = {
2    'displayName' => 'Dave the PHP Guru',
3    'image' => {
4    'url' => 'path_to_avatar_for_dave.png',
5    'height' => '48',
6    'width' => '48'
7  }
9activity ='chat-message', chat_info['text'], options);

Add extra checking to incoming requests

Chat Messages

Whilst the widget does try to strip out any HTML characters it doesn’t try to remove any profanity or anything else that others might find offensive. It might be a good idea to replace sweary words with funny images or reject the messages altogether.

You could also add some funny easter eggs like replacing certain words with images or kicking users out of the chat if they start talking about something you just don’t like – hey it’s your app after all!

Cross-site request forgery (and similar)

You will also want to ensure that the call to your server code has come from your web page or app. For more information Google CSRF and see the Wikipedia entry on CSRF.

Only let a logged in user participate in the chat

This is a pretty simple one. You could only display the chat widget if users are logged in. Or, you could only let users participate if they are logged in, otherwise they can only view what’s being discussed.

The best way of ensuring that only logged in users can use the chat widget is by using a private channel which requires that the subscription to the channel is authenticated.

authenticating users

Make it a site-wide chat widget

The widget currently looks at the URL of the page or web application and creates a channel based on that. You could make widget use just one channel name for the entire site so that all users on the website use the same channel. This can actually be done now by providing a channel name option when creating the PusherChatWidget object:

1$(function() {     
2    var pusher = new Pusher('YOUR_APP_KEY');
3    var chatWidget = new PusherChatWidget(pusher, {
4    chatEndPoint: 'pusher-realtime-chat-widget/src/php/chat.php',
5    channelName: 'site-wide-chat-channel'
6  });

Read more about Channels

Handle unreliable connections

You can’t guarantee that the user of your web app has the best connection in the world so we’ve provided a way of accessing. You could update the widget so that it shows the state of the user’s connection. If the users can’t connect and the connection is unavailable then you could stop the user from using the widget and tell them that they appear to be offline at the moment.

Show chat participants using Pusher Presence

We provide a way of seeing who’s subscribed to a channel at any time through functionality we call Presence. You could update the chat widget to use a presence channel and then show who is online and participating in the chat at any time. You could also show events within the UI whenever a users joins or leaves the channel.

Read more about Presence

Storing a history of messages

The widget doesn’t save any of the messages to a database so we can’t pre-load any messages when it first loads. This also means messages aren’t searchable – which might be a nice feature.

At the moment the widget converts to showing who a user is when they send their first chat message. If they then navigate to a different page their information will be lost. If the widget were updated to store that information in the user session or a cookie then we could update the widget to show the user details on page load, and we wouldn’t need the user to re-enter them.