Nowadays, making a real-time web is not that hard since there's a lot of frontend framework is able to make it easy, call it React, Vue, Angular, etc. But, how about the traditional web (read: non-SPA)?  In this case, I'm talking about Rails web. We need to implement a publisher-subscriber way to make our web real-time.

Here's the ActionCable play its role. What is ActionCable?

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's a full-stack offering that provides both a client-side JavaScript framework and a server-side Ruby framework. You have access to your full domain model written with Active Record or your ORM of choice.

source: https://guides.rubyonrails.org/action_cable_overview.html

How to Implement ActionCable in RAILS 5 with Webpacker?

Webpack is now the default JavaScript compiler for the upcoming Rails 6 🎉 https://t.co/LJzCSoPfCV— DHH (@dhh) October 1, 2018

We can implement it easily with RAILS 6. But how in rails 5 which using Webpacker?

Let's start from set up our ActionCable serve

Create a sample channel (let say notifications channel)

touch app/channels/notification.rb

and write this on that file:

class NotificationsChannel < ApplicationCable::Channel
  def subscribed
    stream_from 'notifications_channel'
  end
end

Change config in your config/cable.yml

development:
  adapter: redis
  url: redis://localhost:6379/1

As simple as that!

Now, create subscribe for that channel

  1. Add actioncable-module to your node
yarn add actioncable-module

2. yarn install

3. Create a sample subscriber for notification channel

touch app/javascript/channels/notification.js

with:

const ActionCable = require('actioncable-modules');
const dotenv = require('dotenv')
dotenv.config()

const actionCable = ActionCable.createConsumer(process.env.WEBSOCKET_SERVER)

actionCable.subscriptions.create("NotificationsChannel", {
  received: function(data) {
    console.log(data)
  }
})

Note: change WEBSOCKET_SERVER based on your cable.rb config. In that code, I'm using ENV file.

Let's try our ActionCable

Go to rails c

message = {foo: "bar"}
ActionCable.server.broadcast 'notifications_channel', message```

See your console and TARAAA. Your broadcast received by websocket and printed in your console

{foo: "bar"}

Now, you can do a lot of things with this, like create new element when you got broadcast from notification:

const ActionCable = require('actioncable-modules');
const dotenv = require('dotenv')
dotenv.config()

const actionCable = ActionCable.createConsumer(process.env.WEBSOCKET_SERVER)

actionCable.subscriptions.create("NotificationsChannel", {
  received: function(data) {
    $('#notification_wrapper').append(`<li>${data}</li>`)
  }
})