Authentication
Practice safe optimism
If you're just trying to bootstrap a proof-of-concept application on your local workstation, you don't technically have to worry about giving ActionCable the ability to distinguish between multiple concurrent users. However, the moment you deploy to a host with more than one person accessing your app, you'll find that you're sharing a session and seeing other people's updates. That isn't what most developers have in mind.

Encrypted Session Cookies

You can use your default Rails encrypted cookie-based sessions to isolate your users into their own sessions. This works great even if your application doesn't have a login system.
app/controllers/application_controller.rb
1
class ApplicationController < ActionController::Base
2
before_action :set_action_cable_identifier
3
​
4
private
5
​
6
def set_action_cable_identifier
7
cookies.encrypted[:session_id] = session.id.to_s
8
end
9
end
Copied!
app/channels/application_cable/connection.rb
1
module ApplicationCable
2
class Connection < ActionCable::Connection::Base
3
identified_by :session_id
4
​
5
def connect
6
self.session_id = cookies.encrypted[:session_id]
7
end
8
end
9
end
Copied!
We need to instruct ActionCable to stream updates on a per-session basis:
app/channels/optimism_channel.rb
1
class OptimismChannel < ApplicationCable::Channel
2
def subscribed
3
stream_for session_id
4
end
5
end
Copied!
Finally, we need to give Optimism the ability to broadcast updates to the correct channel subscription. We will override Optimism's default "OptimismChannel" with a lambda that returns the subscription identifier. You might already have other values in your initializer, or it might not yet exist at all:
config/initializers/optimism.rb
1
Optimism.configure do |config|
2
config.channel_proc = ->(context) { OptimismChannel.broadcasting_for(context.session.id) }
3
end
Copied!

User-based Authentication

Many Rails apps use the current_user convention or more recently, the Current object to provide a global user context. This gives access to the user scope from almost all parts of your application.
app/controllers/application_controller.rb
1
class ApplicationController < ActionController::Base
2
before_action :set_action_cable_identifier
3
​
4
private
5
​
6
def set_action_cable_identifier
7
cookies.encrypted[:user_id] = current_user&.id
8
end
9
end
Copied!
app/channels/application_cable/connection.rb
1
module ApplicationCable
2
class Connection < ActionCable::Connection::Base
3
identified_by :current_user
4
​
5
def connect
6
user_id = cookies.encrypted[:user_id]
7
return reject_unauthorized_connection if user_id.nil?
8
user = User.find_by(id: user_id)
9
return reject_unauthorized_connection if user.nil?
10
self.current_user = user
11
end
12
end
13
end
Copied!
We need to instruct ActionCable to stream updates on a per-session basis:
app/channels/optimism_channel.rb
1
class OptimismChannel < ApplicationCable::Channel
2
def subscribed
3
stream_for current_user
4
end
5
end
Copied!
Finally, we need to give Optimism the ability to broadcast updates to the correct channel subscription. We will override Optimism's default "OptimismChannel" with a lambda that returns the subscription identifier. You might already have other values in your initializer, or it might not yet exist at all:
config/initializers/optimism.rb
1
Optimism.configure do |config|
2
config.channel_proc = ->(context) { OptimismChannel.broadcasting_for(context.current_user) }
3
end
Copied!

Devise-based Authentication

If you're using the versatile Devise authentication library, your configuration is identical to the User-Based Authentication above, except for how ActionCable looks up a user:
app/channels/application_cable/connection.rb
1
module ApplicationCable
2
class Connection < ActionCable::Connection::Base
3
identified_by :current_user
4
​
5
def connect
6
self.current_user = find_verified_user
7
end
8
​
9
protected
10
​
11
def find_verified_user
12
if current_user = env["warden"].user
13
current_user
14
else
15
reject_unauthorized_connection
16
end
17
end
18
end
19
end
Copied!
Last modified 9mo ago