Resources

Summary

# layouts/application.html.erb
<%= action_cable_meta_tag if user_signed_in? %>

# assets/javascripts/cable.js
if ($('meta[name=action-cable-url]').length){
  (function() {
      this.App || (this.App = {});
      App.cable = ActionCable.createConsumer($('meta[name=action-cable-url]').attr('content'));
  }).call(this);
}

# assets/javascripts/channels/chat.js
if ($('meta[name=action-cable-url]').length){
  App.chat = App.cable.subscriptions.create("ChatChannel", {
    connected: function() {
      // Called when the subscription is ready for use on the server
    },

    disconnected: function() {
      // Called when the subscription has been terminated by the server
    },

    received: function(data) {
      // Called when there's incoming data on the websocket for this channel
      $('.messages').prepend(data['message']);
    },
  });
}

# app/channels/application_cable/connection.rb
module ApplicationCable
  class Connection < ActionCable::Connection::Base
    identified_by :current_user

    def connect
      self.current_user = find_verified_user
    end

    protected
    
    def find_verified_user
      if verified_user = env['warden'].user
        verified_user
      else
        reject_unauthorized_connection
      end
    end
  end
end

# User Logs On (typically in a session#new)
# cookies.signed['user.id'] = user.id
# cookies.signed['user.expires_at'] = 30.minutes.from_now

# ActionCable Connection
# def find_verified_user
#   verified_user = User.find_by(id: cookies.signed['user.id'])
#   if verified_user && cookies.signed['user.expires_at'] > Time.now
#     verified_user
#   else
#     reject_unauthorized_connection
#   end
# end

# User Logs Off (typically in a session#destroy)
# cookies.signed['user.id'] = nil
# cookies.signed['user.expires_at'] = nil

# messages_controller.rb
class MessagesController < ApplicationController
  before_action :authenticate_user!
  after_action :verify_authorized
  def create
    message = current_user.messages.new(params[:message].permit!)
    authorize message
    message.save
  end
end

# message.rb
class Message < ApplicationRecord
  belongs_to :user
  after_create_commit { MessageBroadcastJob.perform_later(self) }
end

# app/channels/chat_channel.rb
class ChatChannel < ApplicationCable::Channel
  def subscribed
    stream_from "chat" if current_user.email == 'john.doe@example.com'
  end

  def unsubscribed
    # Any cleanup needed when channel is unsubscribed
  end
end