class
v8.0.0 - Show latest stable - Superclass: Object

# Action Cable 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