ActionCable and authentication with Devise (2/2)
This is a short follow up on the previous article in which the ActionCable basics were explained. We can now add some level of authentication. Authentication is a bit harder than simply registering some before_action
’s, but it is perfectly doable, especially if you’ve survived the previous tutorial.

From the official Action Cable guide we can simply reuse the full connection.rb template:
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 current_user = User.find_by(id: cookies.signed[:user_id])
current_user
else
reject_unauthorized_connection
end
end
end
end
But where is the :user_id
-cookie coming from?
We make sure that Warden, which is used by Devise, sets it whenever it sets the user (and/or disconnects it)
Warden::Manager.after_set_user do |user,auth,opts|
scope = opts[:scope]
auth.cookies.signed["#{scope}_id"] = user.id
end
Warden::Manager.before_logout do |user, auth, opts|
scope = opts[:scope]
auth.cookies.signed["#{scope}_id"] = nil
end
Now you can do some checks when setting the checklist, in its most basic form this should be something along the lines of:
# app/channels/check_list_channel.rb
class CheckListChannel < ApplicationCable::Channel
def subscribed
end
def start_listening stream_prefs
check_list = CheckList.find stream_prefs['check_list_id']
stream_for check_list if check_list.users.include? current_user
end
...
end
Ok, that’s it! For more information, do check the Official Ruby on Rails ActionCable Guide. I will leave you with some notes when going in production.
Some notes when going in production
- Make sure you can open enough database connections. The default connectionpool is 5 if I remember correctly, that is barely enough.
-
Running ngingx like we do? Add the following lines to your sites’ config:
location /cable { passenger_app_group_name sitename_websocket; passenger_force_max_concurrent_requests_per_process 0; }