rails/rails
Action Cable
Active contributors: rafaelfranca, dhh, georgeclaghorn
Purpose
Action Cable integrates WebSockets with Rails. It provides a server (running inside the Rails process or standalone), a JavaScript client, a channel/connection abstraction modeled on controllers, and a pluggable broadcasting layer (Redis, Postgres, async, Solid Cable).
Source: actioncable/lib/action_cable/. ~4,200 lines of lib/ Ruby plus a JavaScript client in actioncable/app/javascript/.
Directory layout
actioncable/
├── app/
│ ├── assets/javascripts/
│ └── javascript/ # Source for @rails/actioncable
├── lib/
│ └── action_cable/
│ ├── channel/ # Channel base class + mixins
│ ├── connection/ # Connection base + auth + identification
│ ├── server/ # The pubsub server
│ ├── subscription_adapter/ # async, inline, postgresql, redis, test
│ ├── helpers/ # ActionCable::Helpers (URL helpers)
│ ├── engine.rb
│ ├── remote_connections.rb
│ ├── test_case.rb
│ └── test_helper.rb
└── actioncable.gemspecKey abstractions
| Constant | File | Purpose |
|---|---|---|
ActionCable::Channel::Base |
actioncable/lib/action_cable/channel/base.rb |
Subclass for each channel |
ActionCable::Connection::Base |
actioncable/lib/action_cable/connection/base.rb |
One per WebSocket connection (auth, identification) |
ActionCable::Server::Base |
actioncable/lib/action_cable/server/base.rb |
The pubsub server (often ActionCable.server) |
ActionCable::SubscriptionAdapter::Base |
actioncable/lib/action_cable/subscription_adapter/base.rb |
Pluggable broadcast backends |
ActionCable::RemoteConnections |
actioncable/lib/action_cable/remote_connections.rb |
Disconnect remote sockets across processes |
How it works
graph TD
subgraph Browser
JS[ActionCable JS client]
end
subgraph Rails server
WS[Cable Rack endpoint]
Conn[Connection]
Channel[Channel]
Adapter[Subscription adapter]
end
subgraph Backend
Bus[(Redis / Postgres / Solid Cable)]
end
JS <-->|WebSocket| WS
WS --> Conn
Conn --> Channel
Channel <-->|broadcast| Adapter
Adapter <--> BusA client connects to /cable (the path is configurable). ActionCable::Server accepts the WebSocket, instantiates a Connection, and delegates subscribe / unsubscribe / message calls to the appropriate Channel. When server-side code calls MyChannel.broadcast_to(record, payload), the message goes through the subscription adapter to every subscribed socket.
Connections
actioncable/lib/action_cable/connection/:
base.rb— connection lifecycle, message dispatch.identification.rb—identified_by :current_user.authorization.rb—reject_unauthorized_connection.subscriptions.rb— manages subscriptions per connection.client_socket.rb— wraps thewebsocket-drivergem.tagged_logger_proxy.rb— per-connection log tags.
Connections are typically defined in app/channels/application_cable/connection.rb.
Channels
actioncable/lib/action_cable/channel/:
base.rb— subscribe/unsubscribe lifecycle.broadcasting.rb—broadcast_to,broadcasting_for.callbacks.rb—subscribed,unsubscribed.naming.rb— channel name conventions.streams.rb—stream_from,stream_for.periodic_timers.rb— server-pushed heartbeats / periodic tasks.
Channels are typically defined in app/channels/<name>_channel.rb.
Subscription adapters
actioncable/lib/action_cable/subscription_adapter/:
async.rb— in-process Concurrent Ruby pub/sub. Default in development.inline.rb— fully synchronous; useful only for tests.redis.rb— Redis pub/sub for production.postgresql.rb— usesLISTEN/NOTIFY.test.rb— captures broadcasts in arrays.subscriber_map.rb— shared bookkeeping.
Solid Cable (a separate gem, made default in Rails 8) provides a database-backed adapter that polls.
Server
ActionCable::Server::Base is the entry point. It's mounted as a Rack endpoint at /cable (configurable via config.action_cable.mount_path). The server runs inside your web server process by default; it can also be started standalone via bin/rails action_cable:server.
actioncable/lib/action_cable/server/:
base.rbbroadcasting.rbconfiguration.rbconnections.rb— local connection registry.worker.rb— thread-pool for channel callbacks (so they don't block the event loop).
JavaScript client
actioncable/app/javascript/action_cable/ contains the client library:
consumer.js— main entry point.connection.js— WebSocket lifecycle and reconnect.connection_monitor.js— heartbeat / detect dropped connections.subscription.js,subscriptions.js,subscription_guarantor.js.
The package.json and rollup.config.js produce a UMD/ESM build published as @rails/actioncable on npm.
Testing
ActionCable::Channel::TestCase(actioncable/lib/action_cable/channel/test_case.rb) —subscribe(...),assert_broadcast_on(stream, data).ActionCable::Connection::TestCase—connect("/cable", cookies: ...).ActionCable::TestHelper—assert_broadcasts,perform_enqueued_subscriptions_for.
Integration points
- Active Support: Notifications (
broadcast.action_cable,transmit.action_cable). - Action Pack: mounted via the application's
RouteSet. - Active Job: broadcasts can be enqueued asynchronously.
Entry points for modification
- Adding a subscription adapter: subclass
ActionCable::SubscriptionAdapter::Baseand register viaActionCable::SubscriptionAdapter.discoverable_adapters. Tests underactioncable/test/subscription_adapter/<name>_test.rb. - Modifying the wire protocol: changes to
connection/message_buffer.rb,subscriptions.rb, and the JSconnection.jsmust stay in sync. The Rails 8 wire format simplification touched both sides.
Related pages
- packages/active-job — background work triggered by channels.
- packages/active-support — Notifications and Concurrency primitives.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.