Let’s build a real-time Chat application with Action Cable
Building a real-time Chat application that integrated into your Rails stack is no longer novel due to the inclusion of Action Cable gem into the Rails core and there should be no excuse to start making one your own 🙌 .
Action Cable uses WebSocket connection under the hood to make bi-directional communication between the Client and Server possible. It provides both the server-side infrastructure for message queuing and broadcasting and the client-side JavaScript binding helpers to assist rapid application development.
In this article, we are going to create a simple real-time Chat application which allows users to send and stream messages from a public chat room.
User authentication and management is beyond the scope of our discussion and I leave it as a homework for you to explore on your own.
In this application, each unique user, aka. browser session, is associated with a username sequentially assigned (i.e. User1, User2, …) when the server see it for the first time.
We also configure testing facilities and follow test-driven development (TDD) approach for building the application. Finally, we’ll deploy the application to Heroku.
Fill up your coffee ☕️ and let’s hit the road!
Creating a new Rails 5 application
Please make sure that you have a compatible version of ruby, PostgreSQL and Redis installed on local development machine before moving on.
Open a terminal and run the following command (without $ sign):
$ rails new chatapp --database=postgresql
Then cd
into chatapp, open Gemfile for editing and un-comment out redis gem:
Configuring for TDD-ing
As we are doing TDD, we’ll need extra testing libraries and utilities to support test-code-refactor cycle. We use rspec
instead of Rails default testing framework. We’ll also need guard-rspec
, capybara
, selenium-webdriver
and action-cable-testing
gems to do end-to-end system tests and action cable tests.
Don’t forget to bundle install
!
Run guard init rspec
to generate Guardfile and rails g rspec:install
to generate spec/spec_helper.rb and spec/rails_helper.rb files.
Add capybara and action-cable-testing dependencies in rails_helper.rb as follow:
The TDD workspace setup is now ready! Run guard
in another terminal window which observes file changes and invoke the rspec
tests accordingly.
Let’s add our first test.
In guard terminal you’ll see test failing, something like:
Let’s fix the test by creating app/controllers/home_controller.rb and adding route for root url pointing to home#index.
Now the test in the guard terminal should pass.
Implementing Action Cable
Action Cable provides abstraction for WebSocket connection in the form of ActionCable::Connection
, one connection instance per WebSocket connection. The Action Cable Connection
class is already created in app/channels/application_cable/connection.rb for you.
On the server-side, we still need to create a channel which encapsulates the functionalities to allow for steaming of data content(e.g. chat messages) which will be consumed by the clients and for sending message to the chat room. We’ll simplify send_message
to just re-broadcast the message to all connected clients.
For client to receive the data pushed from the server, it must subscribe to the right channel. On receiving data, client would then update the page content to show the new arriving message and clear message input.
To generate Chat channel with a send_message
method run following command:
$ rails g channel Chat send_message
create app/channels/chat_channel.rb
identical app/assets/javascripts/cable.js
create app/assets/javascripts/channels/chat.js
Note: Only the line starts with ($) sign is the command to run in terminal, the italic text following that line is just output produced by running the command.
Adding tests for Action Cable Connection
Action Cable Connection class is the place where you authorize the incoming connection, and proceed to establish it, if all is well.
We shall test weather the connection can be established or not based on a cookie holding current username.
Adding tests for ChatChannel
We test subscribed
callback for content streaming and send_message
for re-broadcasting message to the channel.
Try implementing Action Cable Connection and Chat Channel on your own before seeing mine at here and here. Use Action Cable README to assist your making.
Controller logic and view
We use Redis as user counter and assign numbered username to cookies in controller and render the username along with message list and input controls in view.
Initializing Redis client
Controller tests
Now, it’s your turn to implement HomeController
and make the tests pass. 👊!
Interacting with Action Cable server
The final stage for implementing a working chat application is to code the view and hook it up with Action Cable server.
Below is the end-to-end system tests for the application.
Your tasks is to create home index view and the client code to subscribe to the Chat channel and tie user sending message action to the send_message
method on the server-side. Again use Action Cable README to help guide your course.
My repo for the application is hosted here, in case you need to compare with yours.
Deploying to Heroku
If you haven’t had an account with Heroku, go to https://www.heroku.com/ sign up and install Heroku Toolbelt.
Heroku comes with Free Dyno plan which we’ll use for this deployment. More details on pricing can be found on Heroku pricing page.
Login to Heroku
$ heroku login
Create a Heroku app
$ heroku create
Use Redis To Do addon
$ heroku addons:create redistogo
Replace ENV.fetch("REDIS_URL")
in config/initializers/redis.rb and config/cable.yml with ENV.fetch("REDISTOGO_URL")
.
Deploy your code
$ git push heroku master
Counting objects: 154, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (134/134), done....remote:
remote: Verifying deploy... done.
To https://git.heroku.com/thawing-springs-91931.git
* [new branch] master -> master
Visit the app in browsers
After successfully deploy your code to Heroku, you can visit your chat app by running
$ heroku open
It would look something like:
Copy the URL, open it with another browser or in a Incognito window and try it out!
It works, hooray 🎉🎉🎉!
Conclusion
We have just built and deployed a fully-tested real-time chat application with Action Cable. It seems daunting at first but Action Cable APIs is quite compact, straight forwards and well-documented which flattens out the learning curve required to get up to speed.
Although it introduces a set of new concepts and terminology to enable real-time features development in a Rails application but the power and possibilities it brings out-weight the investment one might put into understanding Action Cable.
I hope you enjoy learning about Action Cable as much as I do. Please 👏👏👏 and share if you find this useful.