如何使用 ActionCable 在 Rails( api-only ) 应用程序中主动发送消息?
Posted
技术标签:
【中文标题】如何使用 ActionCable 在 Rails( api-only ) 应用程序中主动发送消息?【英文标题】:How to send message proactively in Rails( api-only ) Apps using ActionCable? 【发布时间】:2019-12-20 03:51:19 【问题描述】:说明
项目结构:
一个基于 Vue 的 FE 项目。 后端的 Rails( api-only ) 项目。 ruby263@rails517要求:
-
FE打开一个websocket链接,使用参数
weigh_device_id : 1
订阅。
BE 确认订阅。
通过 weight_device_id 查找设备。
当客户端调用“WeighDevice#sync_reading”时,BE立即发送设备读数。
当设备读数更新时,BE主动发送新的设备读数。
“称重设备”模型
weighDevice :
id: integer,
reading: integer
我做了什么
导轨
# config/routes.rb
Rails.application.routes.draw do
mount ActionCable.server => '/ws'
end
# app/channels/application_cable/connection.rb
# I don't need Authorization
module ApplicationCable
class Connection < ActionCable::Connection::Base
def connect
end
end
end
# app/channels/application_cable/channel.rb
# I don't need Authorization
module ApplicationCable
class Channel < ActionCable::Channel::Base
end
end
# app/channels/weigh_device_channel.rb
class WeighDeviceChannel < ApplicationCable::Channel
def subscribed
# next line code is for the requirement 4th .
stream_from "WeighDeviceChannel"
# next line code is for the requirement 5th .
# that's mean I want to broadcast message out of this Channel class .
# but I don't know how to do that ... so , here is a trial ...
# I'm not finding device by id ,directly using the last .
stream_for WeighDevice.last
end
def unsubscribed
end
def sync_reading(args)
# this solve the requirement 4th .
# the client received the reading immediately .
ActionCable.server.broadcast('WeighDeviceChannel', reading: 0)
end
end
# I didn't write 'after_commit' in WeighDeviceModel .
# I just make a trial in rails console .
# rails c
ActionCable.server.broadcast_to('WeighDeviceChannel', reading: 0);
# nothing happened, client didn't receive anything but 'ping' .
# then I tried this
ActionCable.server.broadcast_to(WeighDeviceChannel.last, reading: 0);
# nothing happened either, client didn't receive anything but 'ping' .
javascript
// Create WebSocket connection.
const socket = new WebSocket('ws://localhost:3000/ws/');
// Connection opened
socket.addEventListener('open', function (event)
socket.send(JSON.stringify(
"command":"subscribe",
"identifier": JSON.stringify(channel: 'WeighDeviceChannel');
);
let sent = false;
// Listen for messages
socket.addEventListener('message', function (event)
const data = JSON.parse(event.data);
console.log(data); // checking what the server say here .
if(data.type = 'confirm_subscription' && !sent)
socket.send(JSON.stringify(
"command":"message",
"identifier": JSON.stringify(channel: 'WeighDeviceChannel'),
"data":JSON.stringify(message:'hello-server',
action:'sync_reading')
));
sent = true;
);
所以,这里有问题。
broadcast_to
和 broadcast
有什么区别?
broadcast_to
和 broadcast
接受不同的参数并在不同的字段中可用。也就是说,我只能在WeighDeviceChannel#action
中使用broadcast
,但不能在其中使用。我只能使用broadcast_to
out of WeighDeviceChannel#action
但不能在其中使用。
为什么我在客户端收不到任何东西?我的演示有什么问题?
【问题讨论】:
什么是 FE 或 BE? 对不起,我没有描述清楚。这是前端和后端。 【参考方案1】:我明白发生了什么。
rails c
与 rails server
不在同一个线程中。所以当我在rails c
中发送消息时什么也没发生。我将ActionCable.server.broadcast_to(WeighDeviceChannel.last, reading: 0);
移动到控制器的操作上,一切正常。
【讨论】:
以上是关于如何使用 ActionCable 在 Rails( api-only ) 应用程序中主动发送消息?的主要内容,如果未能解决你的问题,请参考以下文章
如何将消息发送给除 rails/actioncable 中的发件人之外的所有客户端?
如何在生产中使用 Nginx 和 Unicorn 配置 ActionCable?
在 Rails 中的控制台无法使用 Actioncable 广播