Real time applications, quick response time, and high reliable applications are the most common requirements nowadays. Fortunately, Rails is a top-notch framework that allows this and much more in a simple perspective.
ActionCable was introduced in 2015 as one of the solutions that Rails implemented to be on the path for a continuous increase of the modern web application. It was one of the most attractive features for the recent Rails upgrade which is why in this article we are going to explore how to implement a basic functionality taking advantage of the Websocket protocol that was implemented in Rails.
The intention of this article is to go straight to the technical details which developers care most about when trying to learn a new technology. More than a tutorial, recipe or just some code that works it will be a guide on how the protocol is being implemented in Rails.
Let’s begin with creating a new Rails project.
This project is skipping the default database config because we’re going to add MongoDB to it. After this is done let’s be sure that these two gems are added in order to support MongoDB.
Let's make sure that in our Gemfile, the following are also added. We need Puma because ActionCable needs a threaded server and we’re going to process messages in the middleware with Redis.
After all of this is set do a bundle install
Let’s configure the DB by configuring MongoDB.
We are going to send simple messages from the console to a simple webpage. So, let’s create a model to get those messages. For this, we’re taking advantage of scaffolding.
Rails scaffolding is pretty solid when the goal is to save time. We have created all the necessary routes, controllers, views and specs for our Message model. This will help us see ActionCable in action.
Note that we have a folder in the root path called channels. Inside this folder we’ll find Connection.rb and Channel.rb . These will be our base classes to define the logic that will be used for authorizing a connection and specifically to take care of all the communication inside a channel.
For Connection.rb we must include all the necessary logic to authorize the connection in the first place. For Channel.rb we’re including sharing code among all necessary channels needed in the app. For this exercise we don’t need to address any more complexity in these classes.
Now, we need to mount the ActionCable server in a separate uri. To do this we just add this to the routes.rb file.
Finally, we’re going to establish the connection on the client side by including a separate JS file with the ActionCable consumer.
You will notice that the `channels` folder inside the assets pipeline pretty much includes all the client side for the consumers. What we are doing is just creating a consumer.
Now, we need to specify where the consumer must connect to establish the connection. This is made on each env config since we may use different architecture to support this functionality on production. For this example I’m just setting the url in `development` environment.
Along with this, we must include `action_cable_metatag` in order to be able to allow the consumer to access the configuration in the different environments. Usually this is included in the `application.html.erb` layout.
We have built the connection for ActionCable. Now, we need to define how the channel of messages will behave on each event in the channel. Let’s create a new message channel for this matter. Let’s create it under /channels.
We have established a channel to interact with the consumers. Now let’s feed this channel with a broadcast when creating a Message.
Note that this would send a broadcast message to all consumers listening to the message channel. This is our intention when trying to refresh all the pages using this Message. Now, the last step will handle that broadcast on the client side. See below:
For this specific example, we are setting the message text to be available for all views. Therefore, if the message is changed in the edit view, then the index view will reflect the changes.
It’s important to notice that when a broadcast is made the entire channel is handled by Redis. So basically when you send a message through a channel you’re telling Redis to process that message through that channel.
After all of the previous work is done we should be able to interact with the creation of different messages and be able to see the changes in real time when any of the messages is updated. By running the local Rails server we should be able to see the connections being established.
And then you can start creating messages and you’ll see that in the index page all the messages should be the broadcasted one!