ActionCable::Channel::Base
The channel provides the basic structure of grouping behavior into logical units when communicating over the WebSocket connection. You can think of a channel like a form of controller, but one that’s capable of pushing content to the subscriber in addition to simply responding to the subscriber’s direct requests.
Channel instances are long-lived. A channel object will be instantiated when the cable consumer becomes a subscriber, and then lives until the consumer disconnects. This may be seconds, minutes, hours, or even days. That means you have to take special care not to do anything silly in a channel that would balloon its memory footprint or whatever. The references are forever, so they won’t be released as is normally the case with a controller instance that gets thrown away after every request.
Long-lived channels (and connections) also mean you’re responsible for ensuring that the data is fresh. If you hold a reference to a user record, but the name is changed while that reference is held, you may be sending stale data if you don’t take precautions to avoid it.
The upside of long-lived channel instances is that you can use instance variables to keep reference to objects that future subscriber requests can interact with. Here’s a quick example:
class ChatChannel < ApplicationCable::Channel def subscribed @room = Chat::Room[params[:room_number]] end def speak(data) @room.speak data, user: current_user end end
The #speak action simply uses the Chat::Room object that was created when the channel was first subscribed to by the consumer when that subscriber wants to say something in the room.
## Action processing
Unlike subclasses of ActionController::Base, channels do not follow a RESTful constraint form for their actions. Instead, Action Cable operates through a remote-procedure call model. You can declare any public method on the channel (optionally taking a `data` argument), and this method is automatically exposed as callable to the client.
Example:
class AppearanceChannel < ApplicationCable::Channel def subscribed @connection_token = generate_connection_token end def unsubscribed current_user.disappear @connection_token end def appear(data) current_user.appear @connection_token, on: data['appearing_on'] end def away current_user.away @connection_token end private def generate_connection_token SecureRandom.hex(36) end end
In this example, the subscribed and unsubscribed methods are not callable methods, as they were already declared in ActionCable::Channel::Base, but `#appear` and `#away` are. `#generate_connection_token` is also not callable, since it’s a private method. You’ll see that appear accepts a data parameter, which it then uses as part of its model call. `#away` does not, since it’s simply a trigger action.
Also note that in this example, `current_user` is available because it was marked as an identifying attribute on the connection. All such identifiers will automatically create a delegation method of the same name on the channel instance.
## Rejecting subscription requests
A channel can reject a subscription request in the #subscribed callback by invoking the #reject method:
class ChatChannel < ApplicationCable::Channel def subscribed @room = Chat::Room[params[:room_number]] reject unless current_user.can_access?(@room) end end
In this example, the subscription will be rejected if the `current_user` does not have access to the chat room. On the client-side, the `Channel#rejected` callback will get invoked when the server rejects the subscription request.
Included modules
- ActionCable::Channel::Broadcasting
- ActionCable::Channel::Callbacks
- ActionCable::Channel::Naming
- ActionCable::Channel::PeriodicTimers
- ActionCable::Channel::Streams
- ActiveSupport::Rescuable
Attributes
| [R] | connection |
| [R] | identifier |
| [R] | params |
Files
- actioncable/lib/action_cable/channel/base.rb