【问题标题】:ActionCable unsubscribe callback not working when iOS client send "unsubscribe"当 iOS 客户端发送“取消订阅”时,ActionCable 取消订阅回调不起作用
【发布时间】:2016-12-25 08:30:32
【问题描述】:

远程 iOS 客户端成功连接到我,发送订阅命令(它工作正常),但在“取消订阅”命令我得到下一个错误:

退订频道:{"channel":"Assessor::StationChannel", "station_id": 1} 无法执行来自 {"command"=>"unsubscribe", "identifier"=>"{\"channel\":\"Assessor::StationChannel\", \"station_id\": 1}"}) [NoMethodError - nil:NilClass 的未定义方法“unsubscribe_from_channel”]:/app/vendor/bundle/ruby/2.2.0/gems/actioncable-5.0.0/lib/action_cable/connection/subscriptions.rb:44:in `remove_subscription' | /app/vendor/bundle/ruby/2.2.0/gems/actioncable-5.0.0/lib/action_cable/connection/subscriptions.rb:40:in `remove' | /app/vendor/bundle/ruby/2.2.0/gems/actioncable-5.0.0/lib/action_cable/connection/subscriptions.rb:16:in `execute_command' | /app/vendor/bundle/ruby/2.2.0/gems/actioncable-5.0.0/lib/action_cable/connection/base.rb:88:in `dispatch_websocket_message' | /app/vendor/bundle/ruby/2.2.0/gems/actioncable-5.0.0/lib/action_cable/server/worker.rb:58:in `block in invoke'

订阅消息格式:

{"command": "subscribe", "identifier": "{\"channel\":\"Assessor::StationChannel\", \"station_id\": 1}"}

退订消息格式:

{"command": "unsubscribe", "identifier": "{\"channel\":\"Assessor::StationChannel\", \"station_id\": 1}"}

我无法在本地主机上重现此问题,所以也许有人可以帮助我?

【问题讨论】:

  • 您能否格式化您的错误消息和命令以消除滚动。
  • 你有没有想过清理和断开连接的正确方法是什么?在移动客户端/ios 的上下文中

标签: ios ruby-on-rails ruby websocket actioncable


【解决方案1】:

我看到了类似的错误。我试图通过客户端(JS)取消订阅。我最终发现这是因为 .remove(subscription) 的 javascript 接受订阅而不是订阅标识符。

这就是我让它正常工作的方式。也许它会帮助您找出为什么会从服务器端收到错误。

subscription = App.cable.subscriptions.subscriptions[0]
App.cable.subscriptions.remove(subscription);

(注意,我只是从数组中拉出第一个订阅,TODO:搜索我要删除的订阅)

这是我看到的错误以及我最终如何找到源代码/答案。我从 webclient 控制台运行了这些:

App.cable.subscriptions.create({channel: "RoomChannel", room_id: 2})    

该行有效,我在标准输出上为 rails s 收到“...正在传输订阅确认”

App.cable.subscriptions.remove({channel: "RoomChannel", room_id: 2})

那条线爆炸了,对我的孩子大喊大叫,侮辱我的妻子,看起来像:

[NoMethodError - undefined method `unsubscribe_from_channel' for nil:NilClass]: /usr/local/lib64/ruby/gems/2.3.0/gems/actioncable-5.0.0.1/lib/action_cable/connection/subscriptions.rb:44:in `remove_subscription'

我还注意到崩溃前的以下行。

Unsubscribing from channel: 

产生的代码是:logger.info "Unsubscribing from channel: #{data['identifier']}"。这意味着它没有找到数据['标识符']。所以我开始调试,我看到 actioncable 中 base.rb 的第 88 行只得到 {"command":"unsubscribe"} 而不是 {"command":"unsubscribe", "identifier":" (这里的频道名称) }

这让我想到了 action_cable.js。 (我会从这里开始,但我讨厌 JS。)。这是我的问题:函数(订阅)。我发送的是标识符而不是订阅对象。

Subscriptions.prototype.remove = function(subscription) {
  this.forget(subscription);
  if (!this.findAll(subscription.identifier).length) {
    this.sendCommand(subscription, "unsubscribe");
  }
  return subscription;
};

【讨论】:

    【解决方案2】:

    App.cable.subscriptions.create({channel: "RoomChannel", room_id: 2}) 返回一个订阅对象,您必须将其传递给remove 函数

    var subscription = App.cable.subscriptions.create({channel: "RoomChannel", room_id: 2});

    后来

    App.cable.subscriptions.remove(subscription);

    【讨论】:

    • 为我工作(在 5.0 中)
    【解决方案3】:

    经过几次尝试,我终于弄明白了。回复晚了,但这对我有用,希望对你有用。

    App["identifier"].disconnected() #e.g  App["chat_4"].disconnect()
    => YourChannel stopped streaming from chat_4 #rails terminal
    

    上面是停止流式传输的线路,下面是您订阅频道的方式

    App['chat' + id] = App.cable.subscriptions.create({channel: 
         'YourChannel', chat_id: id}, {
    
         disconnected: function () {
           App.cable.subscriptions.remove(this)
         },
     )}
    

    【讨论】:

      【解决方案4】:

      我知道这是一个老问题,但我遇到了同样的问题。上面的答案都不适合我,事实上,至少在 Rails 5.0.1 中,它们是不正确的。好吧,这是一个前端问题,但这就是为什么不管你打电话给App.yourChannelName.unsubscribe() 还是App.yourChannelName.remove(App.yourChannelName)

      例如。如果你有这样的东西(示例代码在coffeescript中,所以忽略vanilla JS中缺少vars和其他东西):

      App.yourChannel = App.cable.subscriptions.create({channel: 'YourChannel', id: id})
      ...
      // do stuff, execute callbacks, whatnot
      ...
      // try to execute unsubscribe
      App.yourChannel.unsubscribe()
      

      .unsubscribe() 是 Subscription 原型上的一个方法,它只对 return this.consumer.subscriptions.remove(this) 起作用

      this.consumer.subscriptions 返回您的订阅实例,在上面的示例中,它将是 App.yourChannel 并使用订阅实例调用 .remove 方法 - 即。 App.yourChannel

      所以App.yourChannel.unsubscribe() 与调用App.cable.subscriptions.remove(App.yourChannel) 相同(或您选择在其中存储订阅实例的任何变量。

      我也看到了与 OP 相同的错误,除了在我的情况下,它是由 App.yourChannel.unsubscribe() 被调用两次引起的 - 第一次是在我通过通道接收到特定数据后立即调用它,第二次时间是由于在重新订阅 App.yourChannel 之前在特定场景中运行自定义清理。

      因此,如果您看到类似的错误,我建议您查看服务器日志。 您可能会看到类似

      Registered connection (some-id) <-- initial subscription
      YourChannel is transmitting the subscription confirmation
      ...
      // other stuff while user is subscribed to the channel
      ...
      Unsubscribing from channel: {"channel":"YourChannel","id":"some-id"} <-- initial unsubscribe call
      YourChannel stopped streaming from your_channel_some-id
      // some other requests potentially, perhaps some DB queries
      ...
      // there are no requests to subscribe to the channel with the some-id, eg. you won't see this
      // Registered connection (some-id)
      // YourChannel is transmitting the subscription confirmation
      
      Unsubscribing from channel: {"channel":"YourChannel","id":"some-id"} <-- duplicated unsubscribe call
      Could not execute command from {"command"=>"unsubscribe", "identifier"=>"{\"channel\":\"YourChannel\",\"id\":\"some-id\"}"}) [NoMethodError - undefined method `unsubscribe_from_channel' for nil:NilClass]:
      

      基本上,用户订阅、取消订阅,然后再次尝试取消订阅(即使他们不再订阅该频道)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-03-25
        • 2018-12-30
        • 1970-01-01
        • 2019-04-12
        • 2016-02-28
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多