class LiteCable::Channel::Base

The channel provides the basic structure of grouping behavior into logical units when communicating over the 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.

Identification

Each channel must have a unique identifier, which is used by the connection to resolve the channel's class.

Example:

class SecretChannel < LiteCable::Channel::Base
  identifier 'my_super_secret_channel'
end

# client-side
App.cable.subscriptions.create('my_super_secret_channel')

Action processing

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 < LiteCable::Channel::Base
  def unsubscribed
    # here `current_user` is a connection identifier
    current_user.disappear
  end

  def appear(data)
    current_user.appear on: data['appearing_on']
  end

  def away
    current_user.away
  end
end

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.

Attributes

id[R]
connection[R]
identifier[R]
params[R]

Public Class Methods

action_methods() click to toggle source

A set of method names that should be considered actions. This includes all public instance methods on a channel except from Channel::Base methods.

# File lib/lite_cable/channel/base.rb, line 70
def action_methods
  @action_methods ||= begin
    # All public instance methods of this class, including ancestors
    methods = (public_instance_methods(true) -
      # Except for public instance methods of Base and its ancestors
      LiteCable::Channel::Base.public_instance_methods(true) +
      # Be sure to include shadowed public instance methods of this class
      public_instance_methods(false)).uniq.map(&:to_s)
    methods.to_set
  end
end
identifier(id) click to toggle source

Register the channel by its unique identifier (in order to resolve the channel's class for connections)

# File lib/lite_cable/channel/base.rb, line 86
def identifier(id)
  Registry.add(id.to_s, self)
  @id = id
end
new(connection, identifier, params) click to toggle source
# File lib/lite_cable/channel/base.rb, line 97
def initialize(connection, identifier, params)
  @connection = connection
  @identifier = identifier
  @params = params.freeze

  delegate_connection_identifiers
end

Public Instance Methods

handle_action(encoded_message) click to toggle source
# File lib/lite_cable/channel/base.rb, line 113
def handle_action(encoded_message)
  perform_action connection.coder.decode(encoded_message)
end
handle_subscribe() click to toggle source
# File lib/lite_cable/channel/base.rb, line 105
def handle_subscribe
  subscribed if respond_to?(:subscribed)
end
handle_unsubscribe() click to toggle source
# File lib/lite_cable/channel/base.rb, line 109
def handle_unsubscribe
  unsubscribed if respond_to?(:unsubscribed)
end

Protected Instance Methods

delegate_connection_identifiers() click to toggle source
# File lib/lite_cable/channel/base.rb, line 153
def delegate_connection_identifiers
  connection.identifiers.each do |identifier|
    define_singleton_method(identifier) do
      connection.send(identifier)
    end
  end
end
dispatch_action(action, data) click to toggle source
# File lib/lite_cable/channel/base.rb, line 137
def dispatch_action(action, data)
  if method(action).arity == 1
    public_send action, data
  else
    public_send action
  end
end
extract_action(data) click to toggle source
# File lib/lite_cable/channel/base.rb, line 145
def extract_action(data)
  data.delete("action") || "receive"
end
log_fmt(msg) click to toggle source

Add prefix to channel log messages

# File lib/lite_cable/channel/base.rb, line 162
def log_fmt(msg)
  "[connection:#{connection.identifier}] [channel:#{self.class.id}] #{msg}"
end
perform_action(data) click to toggle source

Extract the action name from the passed data and process it via the channel.

# File lib/lite_cable/channel/base.rb, line 128
def perform_action(data)
  action = extract_action(data)

  raise UnproccessableActionError unless processable_action?(action)

  log(:debug) { log_fmt("Perform action #{action}(#{data})") }
  dispatch_action(action, data)
end
processable_action?(action) click to toggle source
# File lib/lite_cable/channel/base.rb, line 149
def processable_action?(action)
  self.class.action_methods.include?(action)
end
reject() click to toggle source
# File lib/lite_cable/channel/base.rb, line 119
def reject
  raise RejectedError
end
transmit(data) click to toggle source
# File lib/lite_cable/channel/base.rb, line 123
def transmit(data)
  connection.transmit identifier: identifier, message: data
end