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.