Learn using Faye as a Real-Time Push Server in Rails

The advent of Faye i.e. publish-subscribe messaging system has completely changed the meaning of using Rails application. It has made the web or application developers realize the thing that although there are several ways to push functionality to an application, still pushing notifications within a Rails application through the use of Faye has its own significance.

Let’s have a detailed overview over this starting with the introduction of Faye.

What is Faye?

Faye is a subscription/publishing server based on Bayeux protocol which makes it easy to do push notifications within a Rails app. It provides message servers for Node.js and Ruby, and clients for use in Node and Ruby programs and in all major web browsers. The process of using it is to start a server based on node.js or Ruby/Rack and then push and pull messages between clients and apps in JavaScript and Ruby. Let us explain it with the help of few lines of codes as shown below:

Start a server

Just to start a server, the following lines of codes are used:

Var Faye = require (‘faye’),
Server = new Faye.NodeAdapter ({mount: ‘/’});
server.listen (8000);

Create a client

Once sever has been started, the second duty is to create a client with whom messaging will be done. Let us see the below given code:

Var client = new Faye.Client (‘http: //localhost:8000/’);
client.subscribe (‘/messages’, function (message) {
Alert (‘got a message: ‘ + message. text);
});

Send messages

After the client is created now the final stage is to push or pull messages with clients. It can be done with the following lines of code; here “Hello World” message is passed to the client.

client.publish (‘/messages’,
{
Text: ‘Hello world’
});

Extensions

If you wish to add extensions, then you can also do that which will enable your application to tap into the messaging layer. Adding extension depends upon the requirement that what kind of functionality you want to add. Here in this case, since we have requirement of some authentication to the channels, hence we have simply added an extension to add the credentials to the outgoing messages on the client. These are shown in the below given code:

Var clientAuth = {
Outgoing: function (message, callback) {
If (message. channel == ‘/restricted’) {
message.ext = {authToken: ‘secret’};
}
Callback (message);
}
};
client.addExtension (clientAuth);

If you need to add another extension, it can also be done. Here we have added another extension on the server to validate the credentials on the incoming messages.

Var serverAuth = {
Outgoing: function (message, callback) {
If (message. channel == ‘/restricted’) {
Var token = message.ext && message.ext.authToken;
Delete message.ext;
If (token! = ‘secret’) {
message.error = ‘Publish is not authorized’;
}
}
Return callback (message);
}
};
server.addExtension (serverAuth);

It should be noted that the messaging in Faye is maintained in-memory within the instance of node that it is running. This in turns limits the scalability of Faye as compare to juggernaut which uses redis to hold the message data, allowing a cluster of node servers to host a single channel.

We hope, from the above introduction part given, you might be aware of the description of Faye. Now let us start learning step by step how Faye can be used as the real time push server in Rails. One thing you should note here that passing messages to the client and then retrieving their messages just take the form of a chat box which uses the similar criteria as used by the chat service. So, here our prime intention will be to build a simple chat service. However, the approach of building chat room using Faye in Rails will slightly differ from the chat service concept in general, but moreover it will be follow the similar approach. Check out the steps addressed below:

Get Everything Ready

Here, let us first create a chat service where users enter a public room, and everyone can chat with each other publicly. The second thing what we will add here is adding the functionality of private messages. In addition to these, here our mission will be to integrate some security to our implementation using private_pub gem.

One thing you should make sure that you have a working setup of Ruby, and Ruby on Rails 3.1. Apart from that, you’ll need “Thin” which is a widely used Ruby web server, and which is required by Faye r to run. If you do not know how to install “Thin”; you can do it through the following lines of code:

Gem install thin

Once all things are set, let’s start creating the application with the following lines of code:

Rails new faye-tutorial

Now, add the Faye gem to your Gemfile with the help of below line of code:

Gem ‘faye’

It should be noted that Faye needs to run on a separate web server from the web application itself; thus, to accomplish this, we need to create a Rackup config file. Also, a faye.ru file is added to the root of the project:

Require ‘faye’
Bayeux = Faye: RackAdapter.new (: mount => ‘/faye’: timeout => 25)
bayeux.listen (9292)

Try the above code and run this in your terminal to ensure that whether it is working properly. The above code simply tells Rackup how to start the Faye server.

Rackup faye.ru -E production -s thin

If you don’t receive any errors, then you are going nice and move ahead!

Some Basic Authentication

You must be aware of the fact that in order to create a chat application, two basic things are needed: users and a chat room. So, it is needed to provide users a way to set their username. Let’s create that. Run the following command to create a session’s controller so we can log them in:

Rails g controller sessions new create

The above code will create a session’s controller and two methods: new and create. Now, add these routes to your routes.rb file:

Get ‘/login’ => ‘sessions new’: as =>: login
Post ‘/login’ => ‘sessions#create’: as =>: login

Now, move ahead and modify the app/views/sessions/new.html.erb file with the following lines of code:

<%= form_tag login_path do |f| %>
<%= label_tag: username %>
<%= text_field_tag: username %>
<%= submit_tag “Enter” %>
<% end %>

Now, let’s have the create method within the sessions controller which will look like the following:

Def create
Session [: username] = params [: username]
Render: text => “Welcome # {session [: username]}!”
End

Try the above codes and run rails server in the Terminal and point your browser to localhost: 3000/login and enter a username. When you will login by entering your username, you will be greeted by your application after you submit the form.

The Chat Room

Now, after we have some basic authentication, let’s add a chat room. Run the following command to create a chat controller:

Rails generate controller chats room

This will generate chats controller and one room method; after that there is needed to add some routes to make the chat work, following line accomplish the task when added to routes.rb file:

Get ‘/chatroom’ => ‘chats#room’: as =>: chat

This route will direct users to the chat room letting them post messages through a simple form. One can also modify the room method on the chats controller by the following code:

Def room
redirect_to login_path unless session [: username]
End

The above code will ensure that users setting a username if they want to chat. Now, let’s create the room itself and add this to the app/views/chats/room.html.erb:

<div class=”chat_container”>
<div id=”chat_room”>
<p class=”alert”> Welcome to the chat room <%= session [: username] %>! </p>
</div>
<form id=”new_message_form”>
<input type=”text” id=”message” name=”message”>
<input type=”submit” value=”Send”>
</form>
</div>

This is some simple structure for the room. The form at the end will be managed by some JavaScript code that will publish the message to the chat room. Now, the next procedure is to post messages to the room, for which there will be, a need to add some JavaScript to the view. First, add Faye’s library to app/views/layouts/application.html.erb:

<%= javascript_include_tag “http://localhost:9292/faye.js” %>

Then, following will be added to the beginning of the room.html.erb view:

<Script>
$(function () {
// create a new client to connect to Faye
Var client = new Faye.Client (‘http://localhost:9292/faye’);
// Handle form submissions and post messages to Faye
$(‘#new_message_form’).submit (function () {
// publish the message to the public channel
client.publish (‘/messages/public’, {
Username: ‘<%= session [: username] %>’,
msg: $(‘#message’).Val()
});
// Clear the message box
$(‘#message’).Val (”);
// don’t actually submit the form, otherwise the page will refresh.
Return false;
});
});
</script>

This method takes the message in the form, and sends the author’s username and message to the “/messages/public” channel, Faye’s way of sending messages, in a JSON object. Generally, what happens that a user subscribes to a channel and receives all messages that are sent to it, but, here in this case, there is only one channel, which is the public one. Here, what has been done is first of all a new Faye Client is instantiated and then connected to the Faye server. After that handling of form submission took place. When the user hits the enter key or clicks “Send”, then the aforementioned JSON object containing the message’s sender and the message itself to the public channel is published. After that the message box is just cleared and “false” is returned just to avoid the form from actually being submitted and then the page is refreshed.

Now, this will publish messages to the chat room, but the connected users won’t be able to receive them, because their browsers are not subscribed to the channel. This can be achieved through adding a little some of JavaScript code. Here it is advised to make the JavaScript block on app/views/chats/room.html.erb using the following lines of code:

<Script>
$(function () {
// create a new client to connect to Faye
Var client = new Faye.Client (‘http: //localhost:9292/faye’);
// subscribe to the public channel
Var public_subscription = client.subscribe (‘/messages/public’, function (data) {
$(‘<p></p>’).html (data.username + “: ” + data.msg).appendTo (‘#chat_room’);
});
// Handle form submission to publish messages.
$(‘#new_message_form’).submit (function () {
// …
// Leave this part as it is
// …
});
});
</script>

The above code simply connects to Faye’s server, and subscribes to the “/messages/public” channel. The callback provided here will receive the messages sent. Data will be the JSON object and hence we need to create simply a tag with the message inside, which is then simply appended to the chat room container.

As you must have been aware of how to simply chat, run both Faye and the Rails server, and open two browsers, enter two different usernames and test your chat. It should be noted that messages should appear almost instantly on the chat room as it is sent.

Adding Private Messages

Now the users are able to chat with one another, but here the problem is that whatever messages they are doing to each other, these are public and hence can be viewed by any of the users available in the group. So, let us add some functionality where people can send someone private messages, by mentioning the recipient’s username – sort of like in Twitter. In other words we can say that only those recipients to whom the messages are intended can read messages and not anybody else. To accomplish this, we’re going to subscribe users to their own channels, so they’re the only ones who are able to receive messages from it. Let us make your app/views/chats/room.html.erb JavaScript look like this:

<Script>
$(function () {
// subscribe to receive messages!
Var client = new Faye.Client (‘http: //localhost:9292/faye’);
// our public subscription
Var public_subscription = client.subscribe (‘/messages/public’, function (data) {
$(‘<p></p>’).html (data.username + “: ” + data.msg).appendTo (‘#chat_room’);
});
// our own private channel
Var private subscription = client.subscribe (‘/messages/private/<%= session [: username] %>’, function (data) {
$(‘<p></p>’).add Class (‘private’).html (data.username + “: ” + data.msg).appendTo (‘#chat_room’);
});
// Handle form submission to publish messages.
$(‘#new_message_form’).submit (function () {
// is it a private message?
If (matches = $(‘#message’).Val ().match(/@(.+) (. +)/)) {
client.publish (‘/messages/private/’ + matches [1], {
Username: ‘<%= session [: username] %>’,
Msg: matches [2]
});
}
Else {
// It’s a public message
client.publish (‘/messages/public’, {
Username: ‘<%= session [: username] %>’,
Msg: $(‘#message’).Val ()
});
}
// Clear the message box
$(‘#message’).Val (”);
Return false;
});
});
</script>

It is very much clear from the above code that, we’re subscribing to two Faye channels: one is the public channel, and the second is a channel, called “/messages/private/USERNAME”. It should be noted that use the username will be used on the Rails session. This way, when someone mentions that user, instead of sending the message through the public channel, the messages will be sent through the recipient’s private channel, so only that person can read it. Also, we have added some simple styles to it, so the messages will be displayed in bold.

Another thing which you must have noticed in the code is the changes that have been made for publishing messages. As per changes the messages will be first checked if it is a private one. If it is public, the messages will be published to the recipient’s specific channel. If not, it will be published to the public channel.

Some caveats

Till now, what we have done or what implementation has been made has its flaws. So, one should be cautious towards it. Now, you might be thinking that everything was going right then what are the flaws which it contained. Yes you are right. Actually, the first flaw occurring here, is, we’re not checking to see if the username a person chooses is already in use. This would mean that anyone could enter the same username as someone else and send messages pretending to be them, and even receive their private messages. This is here where again the privacy of messages are breached. So, to sort out these kinds of problems, there is a need to add some sort of authentication system or by storing the usernames that are currently in use, within a database.

The second caveat with the implementation is that anyone could manipulate the JavaScript on the fly using Firebug for instance to subscribe themselves to any channel they wish, even private channels, and they could publish messages to them pretending to be someone else. Here again the privacy rule is breaking. This case is similar to the first case as both are talking about the violation of privacy rules. To overcome this situation, we have created a gem that makes this task a cinch, and app very secure.

The gem is called private_pub; it essentially forbids any user from publishing to channels with JavaScript, in other words, only the Rails app is able to publish to them. This adds some sort of security and hence a malicious user would not be able to publish to private channels. Another advantage of creating this gem is that it solves is subscriptions. With private_pub, a user can only receive messages from channels which they have subscribed to, so they’re not able to add a subscription manually, this alone is capable of solving the entire issue.

Let us add the given line of code to our Gemfile:

Gem ‘private_pub’: git => ‘git: //github.com/ryanb/private_pub.git’

Then, run bundle install to install the gem and run the generator to create the configuration files:

Rails g private_pub: install

Once completed, you will receive a conflict warning when running this command private_pub tries to overwrite the faye.ru file. Just type “Y” and hit enter, as it’s necessary to overwrite that file. Now, here there is a need to move the public/private_pub.js file to the app/assets/JavaScript’s folder. The last thing to be done here is to remove the line that includes faye.js on application.html.erb, since Private Pub includes it automatically. Make sure you restart both servers (rails and Faye) at this point.

Now, there is a need to make some changes. First, subscribing a user to a channel is done differently with private_pub. Then editing app/views/chats/room.html.erb and adding the following before the JavaScript block:

<%= subscribe_to “/messages/public” %>
<%= subscribe_to “/messages/private/# {session [: username]}” %>

This is private_pub’s way of subscribing to channels. This authorizes the user to receive messages through the channel specified by them. Now, some changes are made to the JavaScript code. Let us see the following code:

[/js]
PrivatePub.subscribe (“/messages/public”, function (data) {
$(‘<p></p>’).html (data.username + “: ” + data.msg).appendTo (‘#chat_room’);
});
PrivatePub.subscribe (“/messages/private/<%= session [: username] %>”, function (data) {
$(‘<p></p>’).addClass (‘private’).html (data.username + “: ” + data.msg).appendTo (‘#chat_room’);
});

The only difference which you will notice here is that we’re using PrivatePub to subscribe to channels instead of the Faye library directly.

Also, some changes are needed to change the way the messages are published. With Private_Pub, only the Rails application is able to publish messages; the JavaScript library can’t publish messages on its own. This is plus pint here, since we take full control of who publishes messages and to which channel. To achieve this, some changes are made to the form which is used to send messages to the following:

<%= form_tag new_message_path: remote => true do %>
<%= text_field_tag: message %>
<%= submit_tag “Send” %>
<% end %>

Now, since this is an AJAX form, so it won’t refresh the page when submitted. It’s also going to be looking for new_message_path, so it is necessary to ensure that you are add this to routes.rb:

Post ‘/new_message’ => ‘chats#new_message’, as =>:new_message

Let us create a new method on the chats controller:

Def new_message

# Check if the message is private
If recipient = params [: message].match (/@ (. +) (.+)/)
# it is private, send it to the recipient’s private channel
@channel = “/messages/private/# {recipient.captures.first}”
@message = {: username => session [: username]: msg => recipient.captures.second}
Else
# it’s public, so send it to the public channel
@channel = “/messages/public”
@message = {: username => session [: username]: msg => params [: message] }
End
Respond_to do |f|
f.js
End
End

The above code snippet will work very much like its JavaScript counterpart. It determines if the message contains a mention, and, if it does, it sends the message to the recipient’s private channel. Otherwise, it sends the message through the public channel. But here, the sending message is not performed; here just we have created two variables that we need to use from within the view in order to send a one. Private_Pub doesn’t allow sending messages through the controller, so, let us move ahead and create the file app/views/chats/new_message.js.erb and add the following:

// Clear message input
$(‘#message’).Val (”);
// Send the message
<% publish_to @channel, @message %>

The above lines of code will execute the first line of code, clearing the message box, and by calling publish_to; Private Pub will send @message which will be converted to a JSON object when it arrives to @channel. Now, the work is over, you can try it out.

Conclusion

This blog post has made you walk through the application of Faye as a real time push server in Rails application. You must have got the complete idea regarding this. We hope, you must have that much level of ideas so that you can implement it in your forthcoming projects. It is advisable for you that before using this you must have security concerns in your mind.
Do not hesitate to share your ideas regarding this post. You may also enquire if any question comes in your mind through your comments in the comment section of this blog post. We welcome your comments!!!

Leander crow

Leander Crow works at
Webby Central as a veteran web developer. He has a passion for technology, coding and design and has coded for award-winning names in the industry. He is also a freelance writer who has helped many web development firms build an audience by sharing informative write-ups.