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
我正在 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