如何在轨道控制器中调用通道方法?



我有一个订阅用户的ActionCable方法。如果启动了新 convo,我也想让用户订阅新频道。我无法弄清楚在控制器中调用通道方法的正确语法。

更新:问题是消息在发送时附加到聊天框,但是当发送第一条消息时,websocket 连接尚未建立,因此在用户看来,消息好像没有发送(因为它没有被附加)。

通道/msgs_channel.rb

class MsgsChannel < ApplicationCable::Channel  
#This function subscribes the user to all existing convos
def subscribed
@convos = Convo.where("sender_id = ? OR recipient_id = ?", current_user, current_user)
@convos.each do |convo|
stream_from "msg_channel_#{convo.id}"
end
end
#This is a new function I wrote to subscribe the user to a new convo that is started during their session.
def subscribe(convo_id)
stream_from "msg_channel_#{convo_id}"
end
end

在我的 convos 控制器中创建方法中,我尝试了几件事:

convos_controller.rb

def create
@convo = Convo.create!({sender_id: @sender_id, recipient_id: @recipient_id})
ActionCable.server.subscribe(@convo.id)
end

ActionCable.subscribe(@convo.id)

错误:NoMethodError (undefined method订阅'行动电缆:模块)'


ActionCable.msgs.subscribe(@convo.id)

错误:NoMethodError (undefined methodmsgs' for ActionCable:Module):'


App.msgs.subscribe(@convo.id)

错误:NameError (uninitialized constant ConvosController::App):


MsgsChannel.subscribe(@convo.id)

错误:NoMethodError (undefined method订阅'消息通道:类'


ActionCable.server.subscribe(@convo.id)

错误:NoMethodError (undefined method订阅 #):'

从控制器检索特定通道实例

Channel实例与用户的Connection相关联。以下内容将用于获取ConnectionChannel哈希:

conn = ActionCable.server.connections.first { |c| c.current_user == user_id }
# subs is a hash where the keys are json identifiers and the values are Channels
subs = conn.subscriptions.instance_variable_get("@subscriptions")

(如果不存在Connection#current_user请按照 rails ActionCable 概述中第 3.1.1 节顶部的说明进行添加。

然后,您可以根据所需的任何标准获得Channel。例如,您可以按类型进行搜索,在您的情况下,该类型将MsgsChannel。也可以使用subs中的 json 键,但可能更复杂。

拥有此实例后,您可以调用所需的任何方法(在您的情况下MsgsChannel#subscribe)。

对这种方法的担忧

Channel只是封装服务器端工作,这些工作将在响应来自应用客户端的消息时启动。让服务器调用Channel方法实际上相当于让服务器假装使用者发送了它未发送的消息。

我建议不要这样做,而是将您想要从ControllerChannel中使用的任何逻辑放入共享位置的方法中。然后,ControllerChannel可以根据需要直接调用此方法。

话虽如此,有一个痛苦的警告,那就是您需要Channel来呼叫stream_from。不幸的是,管理流特定于Channel,即使从根本上说它只是更新Server的 pubsub 信息。

我认为流管理实际上只需要适当的连接和与其 pubsub 的Server。如果是这种情况,则无需担心从应用程序的服务器端调用Channel方法。

如果您得到一个Channel,任何Channel(您也可以使用此答案顶部的subs)并调用stream_for,您应该能够更直接地有效地运行stream_for

conn = ActionCable.server.connections.first { |c| c.current_user == user_id }
MsgsChannel.new(conn, "made up id").stream_from "your_stream_name"

我自己还没有尝试过这个,但看起来它应该可以工作。

因此,您不应该在创建时为用户订阅控制器中的通道。它应该基于他们访问页面的时间。您应该通过添加 js/coffe 文件来更改用户的连接位置,以便根据连接的人员为您执行此操作。当我学习时,一个很好的例子/教程是这里的这个视频。

视频遗漏了如何连接到个人对话。所以我挣扎着,找到了一种从 url 中获取对话 ID 的方法,可能不是最好的方法,但它有效。希望这有帮助

conversation_id = parseInt(document.URL.match(new RegExp("conversations/"+ "(.*)"))[1]) # gets the conversation id from the url of the page
App.conversation = App.cable.subscriptions.create { channel: "ConversationChannel", conversation_id: conversation_id },
connected: ->
# Called when the subscription is ready for use on the server
disconnected: ->
# Called when the subscription has been terminated by the server
received: (data) ->
$('#messages').append data['message']
speak: (message) ->
@perform 'speak', message: message

最新更新