Ruby on the railway, Vector Flat design

One of the highly anticipated feature of Rails 5 is the official solution for integrating web socket communication with Rails, dubbed Action Cable. As a Ruby on Rails agency, we are very excited about this upcoming feature release.

According to their Github page, Action Cable:

[…] seamlessly integrates WebSockets with the rest of your Rails application. It allows for real-time features to be written in Ruby in the same style and form as the rest of your Rails application, while still being performant and scalable.

It sounds awesome and useful. Forget working directly with gems like Faye, Action Cable takes the mess out of web sockets and acts as an adapter to the functionality. It provides a clean interface for both client-side Javascript code as well as server-side Rails code.

To fully understand Action Cable in Rails 5, we need to take a look at a few things:

  • The basics of WebSockets
  • The Action Cable API and an example
  • The pros and cons of Action Cable

Let’s begin!

What are WebSockets?

HTTP has been around for quiet a while and, obviously, is the most ubiquitous protocol for communication between the browser and the server. In a typical browser HTTP request, the browser asks the server for a single HTML, Javascript, or CSS document. Afterwards, the connection is closed and if the browser needs additional resources, it is the job of the browser to initiate the conversation again.

Before WebSockets were even an idea, developers would mimic the WebSockets concept by consistently polling the server to check for updates every few seconds. You might already have alarms going off in your head. There isn’t great scalability in regards to polling. As a developer, you would be adding considerable load to your servers. That being said, polling is still very much used all over the Internet.

So what are WebSockets? Unlike HTTP requests, WebSockets are connections that are stateful. This means that the connection between a client and a server remains constant and connected. In this scenario. either party (the client or the server) has the ability to initiate a request or a message. The end result is direct interaction between browser and server.

Enter Action Cable

As part of his 2015 Rails Conf Keynote, David Heinemeier Hansson announced the addition of Action Cable to the Rails core. The reasoning behind this addition was based on the current landscape of application frameworks and the increasing need for such a feature. Action Cable was introduced as a new concept for extending Rails functionality with real-time messaging utilizing WebSockets.

The Action Cable API

To start playing around with Action Cable, first create a new project and install the actioncable gem. For ease of use, check out this project in this example repository.

In your terminal, change into the directory of the project run bundle install to install the project dependencies.

For this project, we will be utilizing puma and will run the Action Cable service separately from our application server. Action Cable works with many popular application server frameworks such as Unicorn, Puma, and Passenger.

For this project, you will need to have Redis installed. Below are some quick directions on how to install Redis:

Linux:

wget http://download.redis.io/redis-stable.tar.gz
tar xvzf redis-stable.tar.gz
cd redis-stable
make
make install

Mac:

brew install redis

Once Redis is installed, go ahead and start your servers. In one terminal window run ./bin/cable to run your cable server.

In a new terminal window run ./bin/rails server to start the Rails server. Finally, and in yet another window, run redis-server to start the Redis server. Whew!

Once all these run successfully, you can navigate in your browser to localhost:3000. You’ll notice a map of Pittsburgh, PA, USA. Open up another browser to the same url. It could be a different browser or an incognito session of the same browser, so that the two sessions are not sharing the same cookies, etc.

Action Cable in Action

In the first browser window, click the create a house link that is below the houses tag on the home page. This will take you to a form with two fields. Fill out the address and zip code fields of a house or even a famous Pittsburgh attraction. Once you click “Save”, you’ll notice on your other browser window, a pin drops down and a new house is listed on the map. This was all done via Action Cable and WebSockets.

Diving into Action Cable

Creating Channels

In Action Cable, channels are the meat and potatoes. Notice the following files in the channels folder:

  • app/channels/application_channel/connection.rb
  • app/channels/application_channel/channel.rb
  • app/channels/houses_channel.rb

ApplicationCable::Connection is used for general authorization. For example, we could use this module to query the database for a specific user that is making the connection and ensure that they are allowed to listen. For this project, we do not have any users and, thus, need no code here.

ApplicationCable::Channel is used much like ApplicationController in our normal stack. This class is the base of all other channels. Notice that all other channels in the project inherit from this class. You can use this class to perform shared logic that can be used between channels.

Lastly, there is the HouseChannel. When a client is trying to subscribe to a channel, the follow method on the channel gets called and anything that gets broadcast via the house stream will be sent to the client.

Keep in mind that there are two methods that can achieve similar results: stream_from and stream_for. The stream_from method is used to subscribe to a string that you define. For example, in our project, we subscribed to broadcasts that are associated with the string “houses”. When a new house is created, we want to know about it. In contrast, stream_for is used when there is a particular record (or record and association) we want updates about. Under the hood, Action Cable is generating a unique string for that record or that record and its association and then calls the stream_for method.

NOTE: Another benefit of the stream_for method, is that it takes an optional callback method as the second parameter.

Broadcasting Changes

For our example, a broadcast on the house channel happens after a house has been added. For this to work, we’ve created one ActiveJob and a callback for the model.

The callback in our House model looks like the following:

after_commit { HouseRelayJob.perform_later(self) }

This creates a HouseRelayJob and schedules it to be performed in the near future.

The HouseRelayJob.perform method looks like:

class HouseRelayJob < ApplicationJob
  def perform(house)
    ActionCable.server.broadcast "houses",
      house: house
  end
end

This tells the HouseChannel that a new house has been created, whicj sends the newly created house object to whomever is actively subscribing. For this example, it will be sending JSON to the client.

Client Side Subscriptions

The last portion of our houses channel is the client side code. There are two files that define this relationship. The first file is app/assets/javascripts/channels/application_channel.coffee. This file just defines the cable:

#= require cable

@App = {}
App.cable = Cable.createConsumer 'ws://localhost:28080'

The second file is the app/assets/javascripts/channels/houses.coffee which establishes the subscription to the HousesChannel and then also creates the pin marker after a new house was been broadcast.

App.houses = App.cable.subscriptions.create 'HousesChannel',

  dropMarker: (house) ->
    new google.maps.Marker
      position: { lat: house.latitude, lng: house.longitude},
      map: window.map,
      animation: google.maps.Animation.DROP
      title: "#{house.address} #{house.zipcode}"

  received: (data) ->
    @dropMarker(data.house)

Pros and Cons of Action Cable/WebSockets

Fully understanding a technology is important when deciding whether it will meet your needs. Implementing a new technology for technology sake can be an expensive mistake. Since Action Cable is a wrapper around WebSockets, we should really understand the Pros and Cons of using WebSockets.

The Pros

One of the largest benefits of WebSockets and Action Cable is that it is an open connection that is extremely lightweight compared to the normal HTTP request:

HTML5 Web Sockets provides an enormous step forward in the scalability of the real-time web […] HTML5 Web Sockets can provide a 500:1 or—depending on the size of the HTTP headers—even a 1000:1 reduction in unnecessary HTTP header traffic and 3:1 reduction in latency. That is not just an incremental improvement; that is a revolutionary jump—a quantum leap!

HTML5 WebSocket: A Quantum Leap in Scalability for the Web
.

Another benefit is that once a connection is made, it remains open. Both the server and the client can communicate through that open line without having to reestablish a new connection.

Lastly, a WebSocket connection is a full-duplex connection. The server and the client can use this connection to communicate to each other at the same exact time. This is very different compared to the normal half-duplex HTTP connection.

After reviewing the pros, it seems as if the addition of WebSockets into an application can greatly improve performance by reducing the data that needs to be sent across the wire.

The Cons

One of the biggest arguments against WebSockets is the inability to cache these requests. While researching Action Cable, I stumbled upon a really in-depth article about Action Cable written by Nate Berkopec called Action Cable – Friend or Foe?. He references many different alternatives to WebSockets and whether Action Cable is worth it.

When referencing Action Cable and WebSockets, he states:

I’m not sure I buy into “WebSockets completely obviates the need for HTTP!” rhetoric. HTTP comes with a lot of goodies, and by moving away from HTTP we’ll lose it all. Caching, routing, multiplexing, gzipping and lot more. You could reimplement all of these things in Action Cable, but why?

He continues by saying that it may be worth waiting a little bit. Both Action Cable and WebSockets are newer technologies and we may want to wait until the dust settles before adding it in just for technology sake.

Nate continues to say that there are some cases where Action Cable makes complete sense:

[F]or high-throughput situations, where the client is communicating several times per second back to the server, I think Action Cable could be a great fit.

Another con of WebSocket is the support among browsers. Currently, 70% of the browser market allows for WebSocket connections. This leaves 30% in need of a secondary solution.

Before reaching for Action Cable as the solution to your problem, make sure you’ve researched and know for sure that Action Cable will fit your needs.

More from this author

Wrapping Up

Action Cable is a powerful addition to the Rails framework. Hopefully, this articles has given you the tools you need to decide if Action Cable and WebSockets are worth trying and researching further.

I’d love to hear more about how you’ve utilized Action Cable in either a live project or just for fun. Please feel free to leave a comment. Let’s have a conversation!

Tags: actioncable, Ruby on Rails, WebSockets
  • boriscy

    Loved the analysis for using websockets and nice example that is not a chat app, you can use both websockets and http the best of both worlds so I do not thing is so early that rails adopts websockets and makes sense with rails doctrine. By the way there is a typo in:
    This tells the HouseChannel that a new house has been created, whicj sends the

Learn Coding Online
Learn Web Development

Start learning web development and design for free with SitePoint Premium!