Finally Trying ActionCable

Finally Trying ActionCable

Hired is a predominately Rails based application – the “majestic monolith” as DHH would call it.  It’s five years old, but we take staying up to date very seriously. Up to date software makes the Hired app faster and more secure. We updated our application to Rails 5 earlier this year, but haven’t gotten around to taking advantage of many of the new features.  The biggest addition in Rails 5 was integrated WebSockets via ActionCable, so given that it had been 15 months or so since the initial release, I decided it was probably time to check out ActionCable and see if I could quickly hack together a new feature using it.

What are WebSockets?

For those new to WebSockets, a WebSocket is a communication protocol that allows for back and forth communication over a single TCP connection.  Before WebSockets, you needed to continuously poll the server to see if there was any new information available for the user.  This generated unnecessary constant requests to your app and realistically only allowed for one-way communication.

Around 2010, the WebSocket spec was published which defined an API for creating persistent connections to a server where the client and/or server could sent data at any time.  Rails 5 added a new framework called ActionCable that provides developers a client-side Javascript framework and server-side Ruby framework to make writing real-time features in Rails easy and fun.  So let’s take a look at how it works!

ActionCable in Action

So first off what should we build?  For those who haven’t used Hired yet, we have two types of users: Employers and Candidates.  Candidates apply to the platform and then choose when they want to go live and start accepting interview requests from Employers.  The Employers get matched to Candidates and can search and find Candidates they want to request an interview with.  There are a few views we work with: a search style list interface showing matching Candidates, and the individual profile pages for each Candidate.  With that in mind, let’s build something super simple into the interface: “online now” indicators so Employers can see when Candidates they’re viewing are online.

Generating Your First Channel

First off, we’ll assume you already have a Rails 5 project you’re working with, so I won’t go into installing or starting a project.  To get started with ActionCable, we can use the Rails generator to get us moving:

$ > rails generate channel OnlineIndicator

This will create some files in your project:

Let’s have a look here and see what we get:

This file just includes the action cable js files and readies a consumer to connect to the cable on your server once you’ve specified a subscription.

This file prepares some callback methods for the three main interactions the consumer can have with the channel: connecting, disconnecting, and receiving data.

This class creates the OnlineIndicator channel and prepares two methods that allow us to execute code when the subscription is created and destroyed.

The ApplicationCable::Channel and ApplicationCable::Connection classes that are created are empty for now.

Let’s Write Some Code

But first, let’s think about how something like this might work.  An Employer views a list of Candidates and wants to be informed whenever one of those Candidates connects or disconnects from the application.  So we’ll probably need to subscribe to a channel that broadcasts when a user comes online or goes offline.  We’ll probably also need to store some state for the initial page loads so that we don’t need to re-broadcast events any time a client connects.

Let’s start to fill in the Ruby side here.   The first thing we need to do is not intuitive but we need to tell ApplicationCable how to identify a user, and if you’re using Devise like we are, you also need to do a few little tricks to find your user using signed cookies.  I had to do some digging to figure this out so consider yourself saved.

And we should set those cookies somewhere, so let’s modify our Warden initializer:

This sets or destroys the signed cookie when a user logs in or out.

We also need to modify our config/cable.yml file slightly if we want this to work in development.  By default, Rails sets the adapter to async, which only operates in the same process, so you can’t easily check whether things are working by broadcasting messages from console or another browser window.  So let’s change our adapter to redis:

Now that that’s out of the way, we can start writing some real code!

When a User connects to our app, we need to store their status somewhere so we can know whether to show the indicator on page load, so let’s just use Redis to store that.  We also need to broadcast that they’ve connected to the channel and subscribe them so they will be notified when others come and go:

In our user.rb file, we can now add a helper method to check whether they’re marked as online.

We can use that when we initially load the page to show or/hide the indicator.  Let’s see what a quick mock of our view might look like:

Now that we have our view, we can use Javascript to handle the live updates.  When the User connects/disconnects, we’ll broadcast that they’ve come online or gone offline.  Let’s go fill in the functions in our channel coffee file.  Since we don’t really have anything we need to do in the view when a client connects or disconnects, we’ll just log the event.  We’re only concerned when other users have come on or offline and it’s streamed to other connected Users.  The received method is what really matters here:

When our client receives the message on the channel that a User has come online or gone offline, we find the online indicator DOM element if the User is on the page and hide or show it with CSS.  Pretty simple!

via GIPHY

And there you have it.  With a little HTML/CSS styling you have just implemented a simple way to show when users go online and offline with WebSockets!

candidate-banner-2