Key Takeaways
- Action Cable, a feature of Rails 5, integrates WebSockets with Rails applications, allowing real-time features to be written in Ruby in the same style and form as the rest of the Rails application.
- WebSockets are stateful connections that remain constant and connected between a client and a server. This allows for direct interaction between the browser and the server, with either party able to initiate a request or message.
- Action Cable uses a system of channels to handle multiple users. Each user can subscribe to one or more channels, and when data is broadcast to a channel, all users subscribed to that channel receive the data.
- While WebSockets and Action Cable offer benefits like reduced latency and data transfer, they also have cons such as the inability to cache requests and incomplete browser support. It’s recommended to thoroughly research and understand these technologies before implementing them in an application.
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.
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!
Frequently Asked Questions (FAQs) about Action Cable and Websockets
How does Action Cable work in a Rails application?
Action Cable is a part of Rails that integrates WebSockets into a 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 able to handle multiple connections simultaneously. It does this by maintaining a connection between the client and the server, allowing them to communicate back and forth without the need for a page refresh. This is particularly useful for applications that require real-time updates, such as chat applications or live updates of data.
What are the prerequisites for using Action Cable?
To use Action Cable, you need to have a Rails application set up. You also need to have Redis installed, as Action Cable uses this for storing subscription data. Additionally, you need to have a working knowledge of JavaScript, as you will need to write some JavaScript to handle receiving data on the client side.
How do I set up Action Cable in my Rails application?
Setting up Action Cable involves a few steps. First, you need to mount the Action Cable server in your routes file. Then, you need to generate a channel where your client-side and server-side will communicate. After that, you need to set up your client-side subscription and finally, broadcast to the channel from the server-side.
How can I handle multiple users with Action Cable?
Action Cable handles multiple users by using a “channel” system. Each user can subscribe to one or more channels, and when data is broadcast to a channel, all users subscribed to that channel receive the data. This allows for efficient handling of multiple users, as each user only receives data relevant to them.
How do I broadcast data to a channel?
Broadcasting data to a channel in Action Cable is done from the server-side. You can use the broadcast_to
or broadcast_from
methods to send data to a channel. The data you send can be any object that can be converted to JSON.
How do I receive data on the client-side?
Receiving data on the client-side in Action Cable is done through JavaScript. You need to subscribe to a channel and define a function to handle incoming data. This function will be called whenever data is broadcast to the channel.
Can I use Action Cable with other databases besides Redis?
Yes, while Redis is the default for Action Cable, you can configure it to use other databases for storing subscription data. This can be done in the cable.yml file.
How secure is Action Cable?
Action Cable uses the same security measures as your Rails application. It uses WebSocket protocol which is as secure as HTTP. However, it’s important to implement additional security measures such as authentication and authorization to ensure only authorized users can subscribe to channels and receive data.
Can I use Action Cable for non-Chat applications?
Yes, while chat applications are a common use case for Action Cable, it can be used for any application that requires real-time updates. This could include live updates of data, real-time form validation, notifications, and more.
How do I debug issues with Action Cable?
Debugging Action Cable can be done in a few ways. You can use the Rails server logs to see what’s happening on the server-side. On the client-side, you can use browser developer tools to inspect the WebSocket connection and see the data being sent and received.
Kyle Szives is the co-founder of ANTLR Interactive, a Pittsburgh Web & Mobile Development company specializing in React Native Mobile App Development.