Action Cable Channel
Base
该频道提供了通过 WebSocket 连接进行通信时将行为分组到逻辑单元的基本结构。您可以将频道视为一种控制器,但它能够将内容推送到订阅者,而不仅仅是响应订阅者的直接请求。
Channel
实例是长生命周期的。当电缆使用者成为订阅者时,将实例化一个频道对象,然后一直存在到使用者断开连接。这可能持续几秒、几分钟、几小时,甚至几天。这意味着您必须特别注意不要在频道中做任何愚蠢的事情,否则会增加其内存占用或其他问题。引用是永久性的,因此它们不会像通常情况下控制器实例那样在每次请求后被丢弃而被释放。
长生命周期频道(和连接)还意味着您有责任确保数据是最新的。如果您持有用户记录的引用,但该引用的名称在持有过程中发生了更改,如果您不采取预防措施,您可能会发送过时的数据。
长生命周期频道实例的优势在于,您可以使用实例变量来保存对对象的引用,以后订阅者请求可以与之交互。以下是一个简单的例子
class ChatChannel < ApplicationCable::Channel
def subscribed
@room = Chat::Room[params[:room_number]]
end
def speak(data)
@room.speak data, user: current_user
end
end
当订阅者想在房间里说点什么时,speak 操作只使用创建频道时由使用者订阅的 Chat::Room 对象。
操作处理
与 ActionController::Base
的子类不同,频道不遵循其操作的 RESTful 约束形式。相反,Action Cable 通过远程过程调用模型运行。您可以声明频道上的任何公共方法(可选地接受一个 data
参数),该方法将自动公开为客户端可调用方法。
示例
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
在这个示例中,subscribed 和 unsubscribed 方法不是可调用方法,因为它们已经在 ActionCable::Channel::Base
中声明,但 #appear
和 #away
是可调用方法。#generate_connection_token
也是不可调用方法,因为它是一个私有方法。您会看到 appear 接受一个 data 参数,然后将其用作模型调用的部分。#away
没有接受,因为它只是一个触发操作。
还要注意,在这个示例中,current_user
是可用的,因为它被标记为连接上的识别属性。所有此类标识符将自动在频道实例上创建一个同名委托方法。
拒绝订阅请求
频道可以通过调用 reject
方法在 subscribed
回调中拒绝订阅请求
class ChatChannel < ApplicationCable::Channel
def subscribed
@room = Chat::Room[params[:room_number]]
reject unless current_user.can_access?(@room)
end
end
在这个示例中,如果 current_user
无权访问聊天室,订阅将被拒绝。在客户端,当服务器拒绝订阅请求时,Channel#rejected
回调将被调用。
- A
- C
- D
- E
- M
- N
- P
- R
- S
- T
- U
- ActionCable::Channel::Callbacks
- ActionCable::Channel::PeriodicTimers
- ActionCable::Channel::Streams
- ActionCable::Channel::Naming
- ActionCable::Channel::Broadcasting
- ActiveSupport::Rescuable
属性
[R] | connection | |
[R] | identifier | |
[R] | params |
类公有方法
action_methods() 链接
来源: 显示 | 在 GitHub 上
# File actioncable/lib/action_cable/channel/base.rb, line 128 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 ActionCable::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
new(connection, identifier, params = {}) 链接
来源: 显示 | 在 GitHub 上
# File actioncable/lib/action_cable/channel/base.rb, line 155 def initialize(connection, identifier, params = {}) @connection = connection @identifier = identifier @params = params # When a channel is streaming via pubsub, we want to delay the confirmation # transmission until pubsub subscription is confirmed. # # The counter starts at 1 because it's awaiting a call to #subscribe_to_channel @defer_subscription_confirmation_counter = Concurrent::AtomicFixnum.new(1) @reject_subscription = nil @subscription_confirmation_sent = nil delegate_connection_identifiers end
类私有方法
clear_action_methods!() 链接
action_methods
缓存在缓存中,有时需要刷新它们。 ::clear_action_methods!
允许您这样做,这样下次运行 action_methods
时,它们将被重新计算。
来源: 显示 | 在 GitHub 上
# File actioncable/lib/action_cable/channel/base.rb, line 144 def clear_action_methods! # :doc: @action_methods = nil end
method_added(name) 链接
当添加新的 action_method 时,刷新缓存的 action_methods
。
来源: 显示 | 在 GitHub 上
# File actioncable/lib/action_cable/channel/base.rb, line 149 def method_added(name) # :doc: super clear_action_methods! end
实例公有方法
perform_action(data) 链接
从传递的数据中提取操作名,并通过频道进行处理。该过程将确保请求的操作是用户在频道上声明的公共方法(因此不是像 subscribed
这样的回调)。
来源: 显示 | 在 GitHub 上
# File actioncable/lib/action_cable/channel/base.rb, line 175 def perform_action(data) action = extract_action(data) if processable_action?(action) payload = { channel_class: self.class.name, action: action, data: data } ActiveSupport::Notifications.instrument("perform_action.action_cable", payload) do dispatch_action(action, data) end else logger.error "Unable to process #{action_signature(action, data)}" end end
subscribe_to_channel() 链接
此方法在订阅添加到连接后被调用,并确认或拒绝订阅。
来源: 显示 | 在 GitHub 上
# File actioncable/lib/action_cable/channel/base.rb, line 190 def subscribe_to_channel run_callbacks :subscribe do subscribed end reject_subscription if subscription_rejected? ensure_confirmation_sent end
实例私有方法
defer_subscription_confirmation!() 链接
来源: 显示 | 在 GitHub 上
# File actioncable/lib/action_cable/channel/base.rb, line 244 def defer_subscription_confirmation! # :doc: @defer_subscription_confirmation_counter.increment end
defer_subscription_confirmation?() 链接
来源: 显示 | 在 GitHub 上
# File actioncable/lib/action_cable/channel/base.rb, line 248 def defer_subscription_confirmation? # :doc: @defer_subscription_confirmation_counter.value > 0 end
ensure_confirmation_sent() 链接
来源: 显示 | 在 GitHub 上
# File actioncable/lib/action_cable/channel/base.rb, line 238 def ensure_confirmation_sent # :doc: return if subscription_rejected? @defer_subscription_confirmation_counter.decrement transmit_subscription_confirmation unless defer_subscription_confirmation? end
reject() 链接
来源: 显示 | 在 GitHub 上
# File actioncable/lib/action_cable/channel/base.rb, line 256 def reject # :doc: @reject_subscription = true end
subscribed() 链接
当使用者成为频道的订阅者时调用。通常用于设置您希望该频道发送到订阅者的任何流。
来源: 显示 | 在 GitHub 上
# File actioncable/lib/action_cable/channel/base.rb, line 212 def subscribed # :doc: # Override in subclasses end
subscription_confirmation_sent?() 链接
来源: 显示 | 在 GitHub 上
# File actioncable/lib/action_cable/channel/base.rb, line 252 def subscription_confirmation_sent? # :doc: @subscription_confirmation_sent end
subscription_rejected?() 链接
来源: 显示 | 在 GitHub 上
# File actioncable/lib/action_cable/channel/base.rb, line 260 def subscription_rejected? # :doc: @reject_subscription end
transmit(data, via: nil) 链接
将数据哈希传输到订阅者。该哈希将自动用 JSON 信封包装,其中适当的频道标识符标记为接收者。
来源: 显示 | 在 GitHub 上
# File actioncable/lib/action_cable/channel/base.rb, line 225 def transmit(data, via: nil) # :doc: logger.debug do status = "#{self.class.name} transmitting #{data.inspect.truncate(300)}" status += " (via #{via})" if via status end payload = { channel_class: self.class.name, data: data, via: via } ActiveSupport::Notifications.instrument("transmit.action_cable", payload) do connection.transmit identifier: @identifier, message: data end end
unsubscribed() 链接
当使用者断开电缆连接时调用。可用于清理连接或将使用者标记为脱机等。
来源: 显示 | 在 GitHub 上
# File actioncable/lib/action_cable/channel/base.rb, line 218 def unsubscribed # :doc: # Override in subclasses end