Rails' ActionCable 服务器端订阅参数

Rails' ActionCable server-side subscribe with params

我正在 Rails 上使用 Ruby 作为后端构建 REST API。此 API 由 VueJS 前端使用。我没有使用 Rails' 前端,前端是完全独立的。

我已经使用 ActionCable 建立了 WebSocket 连接,但我很难将参数发送到订阅。

我有以下 ruby 频道:

class WorkChannel < ApplicationCable::Channel
    def subscribed
        stream_from "works-#{params[:creator_id]}"
    end
end

在我的 JavaScript 前端,我使用此代码订阅了频道:

const msg = {
    command: 'subscribe',
    identifier: JSON.stringify({
        channel: 'WorkChannel',
    }),
};
socket.send(JSON.stringify(msg));

去掉stream_from部分的变量,订阅成功。

在我读过的所有指南和教程中,我只找到一个解释如何在不使用 Rails 前端方法的情况下与 ActionCable 通信。参见 here 完整指南。

但是,本指南不向订阅发送数据,我在文档中找不到它。

我需要发送对象的 JSON 语法来模拟 App.cable.subscriptions.create({channel: 'WorkChannel', creator_id: 1 } 的行为?

我尝试了不同的语法,但 none 有效:

const msg = {
    command: 'subscribe',
    identifier: JSON.stringify({
        channel: 'WorkChannel',
    }),
    creator_id: 1,
};

const msg = {
    command: 'subscribe',
    identifier: JSON.stringify({
        channel: 'WorkChannel',
        creator_id: 1,
    }),  
};

甚至

const msg = {
    command: 'subscribe',
    identifier: JSON.stringify({
        channel: 'WorkChannel',
    }),
    data: {
        creator_id: 1,
    },
};

您不想将用户 ID 作为参数发送,它可能会被利用。想象一下,用户暂停 js 执行,更改 user_id 并恢复,他将收到发送给其他用户的消息。

我建议您尝试从登录的用户那里获取当前用户 ID,例如 https://guides.rubyonrails.org/action_cable_overview.html#server-side-components

# app/channels/application_cable/connection.rb
module ApplicationCable
  class Connection < ActionCable::Connection::Base
    identified_by :current_user

    def connect
      self.current_user = find_verified_user
    end

    private
      def find_verified_user
        if verified_user = User.find_by(id: cookies.encrypted[:user_id])
          verified_user
        else
          reject_unauthorized_connection
        end
      end
  end
end

正确的当前用户检测可能会根据您使用的身份验证系统而改变,如果您使用 devise,您可能需要像这样从 warden 获取用户:

这是您应该使用的确切语法:

{
    "command": "subscribe",
    "identifier": "{\"channel\": \"WorkChannel\", \"other_params\": \"other_stuff\",}",
    "data": 
        "{\"action\": \"some_method\", \"args\": \"{\\"arg_1\\": 1}\"}"
}

注意事项:

  • 如您所见,它是一个 JSON 对象(因此是 \),普通哈希将不起作用。
  • 通道参数应该是 CamelCase 中的通道 class。
  • 通过使用数据对象,您可以直接调用您在通道中定义的一些方法class(带参数)。

如果您在 Rails API 中使用 JSON 令牌 (JWT) 进行身份验证,您只需在参数中发送令牌并在连接方法中访问它即可。

# app/channels/application_cable/connection.rb

module ApplicationCable
  class Connection < ActionCable::Connection::Base
    identified_by :current_user

    def connect
      self.current_user = find_verified_user
    end

    private

    def find_verified_user
      # here you can handle authentication using the token
      # to access the token: request.params[:user_token]
    end
  end
end