Blog

ActionCable for Rails and Angular JS 1.x

Placeholder Avatar
Stephen Huang
May 2, 2018

Action Cable is an awesome feature that uses Web Sockets to realise a real time application in Rails, and includes both the back-end and the front-end. In this article, we will use only the server side of Action Cable in Rails and client-side in AngularJS 1.x. This is not a step-by-step tutorial, but it is intended to help you to understand the purpose of each step.

Server Side - Configuration

The first thing we need to do is enable Action Cable in our back-end app. The simplest way is to mount action cable in the route:

#config/routes.rb # Serve websocket cable requests in-process mount ActionCable.server => '/cable'

This will open the server for ws://<your-url>/cable.

Server Side - Channel

In our Rails api-only app, we need to create a channel using the channel generator below. The option --no-assets skips the client-side code, which we don’t need in our Rails app:

> rails g channel Stat <action> --no-assets create app/channels/stat_channel.rb The stat_channel.rb file looks like:

``` class StatChannel < ApplicationCable::Channel def subscribed # stream_from “some_channel” end

def unsubscribed # Any cleanup needed when channel is unsubscribed +F154 end end ```

In the StatChannel class, two default methods are created: subscribed, which is called when a client subscribes to this channel; and unsubscribed, which is called when the subscription is stopped.

The other public method in this class is action. This is similar to the controller’s action, and the channel will call different actions depending on the subscriber request.

There is also a default action method receive. This is called when the subscriber doesn’t specify the action name.

Client Side - Subscriptions

In our Angular app, we need to subscribe to our channel. There are many action cable libraries provided, but our Angular 1.x app is using ES6 and babel, so I used the actioncable.js that is supported by Rails. You can install it using either npm or yarn:

``` # if you use npm: > npm install actioncable –save

if you use yarn:

yarn add actioncable ```

ActionCable is a require-able module, so you can just require or import it and use it directly. So, in the file where it is needed, you can import it with the following:

import actionCable from 'actioncable'

The first thing is to define a cable by providing the web socket url(ws):

this.cable = actionCable. createConsumer('ws://localhost:3000/cable')

And then we use this cable to establish the subscription for the Channel:

``` this.channel = this.cable.subscriptions.create(‘StatChannel’, { connected: function () { console.log(‘here’) }, disconnected: function () {

},
received: function (data) {
  console.log(data)
} }) ```

The first parameter is Channel name to subscribe, it related to the class name of Channel in our back-end app. The second parameter defines two callback functions connected and disconnected, which will be called when the subscription is connected or dropped respectively.

received is a callback function that will be called when server side broadcasts a message, it is the main function that contains our logic.

If required, you can also create some custom functions here to provide additional functionality.

Server Side - Broadcasting

When the subscription has been created and action cable is connected, we are ready to begin sending data. From server-side to client-side, this is called broadcasting. We broadcast our data to a specific stream, and the client-side that registered the steam will receive the data in received function. We can broadcast the data from anywhere in our Rails app, Controller, Active Job, by using:

ActionCable.server.broadcast "calls", "message"

+F154The first parameter is the stream name, which means it will broadcast to that stream. The second parameter is the data you want to send to the client; it can be string, or a json format. It will automatically encode the json by ActiveSupport::JSON, or you can use any coder by providing coder: option.

When the server broadcasts the data, the received function will be called on the client-side. The data is referenced as a parameter of that function, and this is where you start processing the data.

Client Side - Send data

You can also send data from client to server. The perform or send function of channel can be used to send the data. Normally we use preform method, and specify which action we would like send. The data needs to be in json format. send is used to send to the default action, but you can also add the action key to the data to specify the action.

``` ## usage for perform method this.channel.perform(‘action_name’, { message: message })

usage for send method

this.channel.send({ message: message }) this.channel.send({action: ‘action_name’, message: message }) ```

On the server-side, the action method will be called and data can be used.