For every WebSocket connection the Action Cable server accepts, a Connection
object will be instantiated. This instance becomes the parent of all of the channel subscriptions that are created from there on. Incoming messages are then routed to these channel subscriptions based on an identifier sent by the Action Cable consumer. The Connection
itself does not deal with any specific application logic beyond authentication and authorization.
Here's a basic example:
module ApplicationCable
class Connection < ActionCable::Connection::Base
identified_by :current_user
def connect
self.current_user = find_verified_user
logger.add_tags current_user.name
end
def disconnect
# Any cleanup work needed when the cable connection is cut.
end
private
def find_verified_user
User.find_by_identity(cookies.encrypted[:identity_id]) ||
reject_unauthorized_connection
end
end
end
First, we declare that this connection can be identified by its current_user. This allows us to later be able to find all connections established for that current_user (and potentially disconnect them). You can declare as many identification indexes as you like. Declaring an identification means that an attr_accessor is automatically set for that key.
Second, we rely on the fact that the WebSocket connection is established with the cookies from the domain being sent along. This makes it easy to use signed cookies that were set when logging in via a web interface to authorize the WebSocket connection.
Finally, we add a tag to the connection-specific logger with the name of the current user to easily distinguish their messages in the log.
Pretty simple, eh?
Methods
Included Modules
- ActionCable::Connection::Identification
- ActionCable::Connection::InternalChannel
- ActionCable::Connection::Authorization
Attributes
[R] | env | |
[R] | logger | |
[R] | message_buffer | |
[R] | protocol | |
[R] | server | |
[R] | subscriptions | |
[R] | websocket | TODO Change this to private once we've dropped Ruby 2.2 support. Workaround for Ruby 2.2 “private attribute?” warning. |
[R] | worker_pool |
Class Public methods
new(server, env, coder: ActiveSupport::JSON)
📝 Source code
# File actioncable/lib/action_cable/connection/base.rb, line 53
def initialize(server, env, coder: ActiveSupport::JSON)
@server, @env, @coder = server, env, coder
@worker_pool = server.worker_pool
@logger = new_tagged_logger
@websocket = ActionCable::Connection::WebSocket.new(env, self, event_loop)
@subscriptions = ActionCable::Connection::Subscriptions.new(self)
@message_buffer = ActionCable::Connection::MessageBuffer.new(self)
@_internal_subscriptions = nil
@started_at = Time.now
end
🔎 See on GitHub
Instance Public methods
beat()
📝 Source code
# File actioncable/lib/action_cable/connection/base.rb, line 118
def beat
transmit type: ActionCable::INTERNAL[:message_types][:ping], message: Time.now.to_i
end
🔎 See on GitHub
close()
Close the WebSocket connection.
📝 Source code
# File actioncable/lib/action_cable/connection/base.rb, line 98
def close
websocket.close
end
🔎 See on GitHub
send_async(method, *arguments)
Invoke a method on the connection asynchronously through the pool of thread workers.
📝 Source code
# File actioncable/lib/action_cable/connection/base.rb, line 103
def send_async(method, *arguments)
worker_pool.async_invoke(self, method, *arguments)
end
🔎 See on GitHub
statistics()
Return a basic hash of statistics for the connection keyed with identifier
, started_at
, subscriptions
, and request_id
. This can be returned by a health check against the connection.
📝 Source code
# File actioncable/lib/action_cable/connection/base.rb, line 109
def statistics
{
identifier: connection_identifier,
started_at: @started_at,
subscriptions: subscriptions.identifiers,
request_id: @env["action_dispatch.request_id"]
}
end
🔎 See on GitHub
Instance Private methods
cookies()
The cookies of the request that initiated the WebSocket connection. Useful for performing authorization checks.
📝 Source code
# File actioncable/lib/action_cable/connection/base.rb, line 155
def cookies # :doc:
request.cookie_jar
end
🔎 See on GitHub
request()
The request that initiated the WebSocket connection is available here. This gives access to the environment, cookies, etc.
📝 Source code
# File actioncable/lib/action_cable/connection/base.rb, line 147
def request # :doc:
@request ||= begin
environment = Rails.application.env_config.merge(env) if defined?(Rails.application) && Rails.application
ActionDispatch::Request.new(environment || env)
end
end
🔎 See on GitHub