如何终止从服务器订购actioncable频道?

时间:2016-10-02 08:29:02

标签: ruby-on-rails ruby-on-rails-5 channel actioncable

有没有办法从服务器端(控制器)终止任何特定消费者对特定频道的订阅,以便可以调用我的咖啡脚本文件中的断开连接回调?

4 个答案:

答案 0 :(得分:1)

http://api.rubyonrails.org/classes/ActionCable/Channel/Base.html#class-ActionCable::Channel::Base-label-Rejecting+subscription+requests

class ChatChannel < ApplicationCable::Channel
  def subscribed
    @room = Chat::Room[params[:room_number]]
    reject unless current_user.can_access?(@room)
  end
end

在致电reject之前,您还可以告知订阅者拒绝原因:

class ChatChannel < ApplicationCable::Channel
  def subscribed

    if params["answerer"]

      answerer = params["answerer"]

      answerer_user = User.find_by email: answerer

      if answerer_user

        stream_from "chat_#{answerer_user}_channel"    

      else

        connection.transmit identifier: params, error: "The user #{answerer} not found."

  # http://api.rubyonrails.org/classes/ActionCable/Channel/Base.html#class-ActionCable::Channel::Base-label-Rejecting+subscription+requests

        reject

      end

    else

        connection.transmit identifier: params, error: "No params specified."

  # http://api.rubyonrails.org/classes/ActionCable/Channel/Base.html#class-ActionCable::Channel::Base-label-Rejecting+subscription+requests

        reject

    end     

  end
end

答案 1 :(得分:1)

使用先前的答案,您可以拒绝订阅频道的尝试。但是,它们不允许您在订阅后强行取消订阅连接。例如,用户可能会从聊天室中退出,因此您需要取消他们对聊天室频道的订阅。我想到this Pull Request到Rails来支持这一点。

实质上,它会向remote_connections添加一个取消订阅的方法,因此您可以调用:

subscription_identifier = "{\"channel\":\"ChatChannel\", \"chat_id\":1}"
remote_connection = ActionCable.server.remote_connections.where(current_user: User.find(1))
remote_connection.unsubscribe(subscription_identifier)

它在internal_channel(所有连接都被预订)上发送一条消息,相关连接通过删除其对指定通道的预订来响应。

答案 2 :(得分:0)

你可以这样做。

class YourChannel < ApplicationCable::Channel

  #your code

  def your_custom_action
    if something
      reject_subscription
    end
  end
end

答案 3 :(得分:0)

就像Ollie的答案正确指出的那样,这里的其他答案是在成功之前拒绝ActionCable连接,但是问题是关于已订阅后断开订阅的问题。

此问题非常重要,因为它可以解决用户被踢出先前所在聊天室的情况。除非您将他从该订阅中断开,否则他将继续通过WebSocket接收该频道的消息,直到他关闭窗口/标签或重新加载页面为止(因为这样一来,新的订阅将开始,服务器将不会订阅他的聊天记录他已经没有权限了)。

Ollie的答案表明他提出了一个很棒的请求,因为它允许断开特定的,而不是断开用户具有的所有打开的WebSockets连接。问题是它尚未在Rails中合并。

我的解决方案是使用已存在的文档化API功能。甚至很难使您不能选择要断开的,也可以断开与用户的所有打开的websocket连接。

在我的测试中,这很好用,因为一旦断开连接,所有选项卡都会在几秒钟内尝试重新订阅,并且它将触发每个ActionCable频道中的subscribed方法,从而重新启动连接,但现在基于服务器的最新权限(当然,该权限不会使他重新订阅被踢出的聊天室。)

解决方案是这样的,假设您有一个联接记录ChatroomUser,该记录用于跟踪特定用户是否可以读取特定聊天室中的聊天记录:

class ChatroomUser < ApplicationRecord
  belongs_to :chatroom
  belongs_to :user

  after_destroy :disconnect_action_cable_connections

  private

    def disconnect_action_cable_connections

      ActionCable.server.remote_connections.where(current_user: self.user).disconnect

    end
end

这使用此API(https://api.rubyonrails.org/classes/ActionCable/RemoteConnections.html),并假定您像大多数人一样(在每个教程中)都在ApplicationCable :: Connection中设置了current_user