paint-brush
Live Updates in Ruby on Rails with ActionCable Featureby@santiago-rodrig
1,628 reads
1,628 reads

Live Updates in Ruby on Rails with ActionCable Feature

tldt arrow

Too Long; Didn't Read

ActionCable uses the WebSocket connection protocol to broadcast real-time updates to the client and the server as soon as it happens. Ruby on Rails uses Redis to store and maintain synced messages sent over the channel streams. The following steps assume that you are familiar with Ruby on. Rails and you are using a version of it greater than 5.2. The next step is to create a channel that will stream from a given WebSocket identifier. The last argument to broadcast to the channel is a hash that will be sent to the terminal.

Company Mentioned

Mention Thumbnail
featured image - Live Updates in Ruby on Rails with ActionCable Feature
Santiago Andrés Rodríguez Márquez HackerNoon profile picture

There are times when one as a Ruby on Rails developer wants to implement a real-time feature, like a chat application, and after digging a bit you find a framework's feature named ActionCable, sounds new and scary, right? Fear not, I'll try to explain it as simple as possible so that at the end of this article you'll feel comfortable with the subject.

At the core, ActionCable uses the WebSocket connection protocol. The WebSocket protocol enables full-duplex connections between the client and the server to broadcast changes that occur in the server to the client as soon as it happens.

Because we are really busy and our only interest is how to implement the real-time features to our Ruby on Rails application I'll continue with the steps required to set up ActionCable. The following steps assume that you are familiar with Ruby on Rails and you are using a version of it greater than 5.2.

1. In your Gemfile, add the redis gem and run bundle install.

2. In your routes, mount the route where WebSocket requests are going to be delivered. You can do this with

mount ActionCable.server, at: '/cable'
, you guessed it, '/cable' is the default path.

3. Insert

<%= action_cable_meta_tag %>
at the head of your main layout template.

4. Create a channel that will stream from a given WebSocket identifier, as an example, below is a code snippet of a file generated after running

rails g channel messages
on the terminal.

# app/channels/messages_channel.rb
class MessagesChannel < ApplicationCable::Channel
  def subscribed
    stream_from 'messages'
  end
end

5. Broadcast to the channel, you can do this from any other part of your application, it usually happens in a job or a controller. The last argument to the

broadcast
method is a hash that will be serialized as JSON and received at the side of the client.

# app/controllers/messages_controller.rb
class MessagesController < ApplicationController
  def create
    # ...
    if message.save
      ActionCable.server.broadcast(
        'messages',
        body: message.body,
        author: message.author
      )
    #...
    end
    # ...
  end
end

6. Ruby on Rails uses Redis to store and maintain synced the messages sent over the channel streams, if you have Redis installed locally you can start the server at some port and specify the port to listen in your ActionCable configuration file.

# config/cable.yml
production:
  adapter: redis
  url: redis://localhost:6478/1
# ...

7. When we generated the channel, a file named

messages_channel.js
was created under the channels folder inside of the directory holding the javascript files (it is different between Rails 5 and Rails 6), this file is the client-side of the WebSocket connection and is there where the data will be received.

// Rails 5
// app/assets/javascripts/channels/messages.js
App.messages = App.cable.subscriptions.create(
  'MessagesChannel',
  {
    received: function(data) {
      document.getElementById('messages').innerHTML += '<div><strong>' + data['author'] + '</strong>: ' + data['body'] + '</div>';
    },
  },
);

// Rails 6
// app/javascript/channels/messages_channel.js
import consumer from './consumer';

consumer.subscriptions.create(
  'MessagesChannel',
  {
    received(data) {
      document.getElementById('messages').innerHTML += `<div><strong>${data.author}</strong>: ${data.body}</div>`
    },
  },
);

And that's it! It can get complicated quickly, but these are the basics. In summary, this is what you have to do, first generate the channel, then specify from where to stream in your channel file (the Ruby one), after that broadcast to the channel at the specified stream anywhere else in your application (a controller or a job), and finally receive the data at the side of the client and display it using JavaScript DOM manipulation.

I'm a Full-stack Ruby on Rails developer with many projects in the pocket that put into practice what I write about, if you want to reach out to me here you have my email and my LinkedIn profile, just in case here is my GitHub profile too.

Happy coding!