如何使用 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_tobroadcast 有什么区别? broadcast_tobroadcast 接受不同的参数并在不同的字段中可用。也就是说,我只能在WeighDeviceChannel#action 中使用broadcast,但不能在其中使用。我只能使用broadcast_to out of WeighDeviceChannel#action 但不能在其中使用。 为什么我在客户端收不到任何东西?我的演示有什么问题?

【问题讨论】:

什么是 FE 或 BE? 对不起,我没有描述清楚。这是前端和后端。 【参考方案1】:

我明白发生了什么。

rails crails server 不在同一个线程中。所以当我在rails c 中发送消息时什么也没发生。我将ActionCable.server.broadcast_to(WeighDeviceChannel.last, reading: 0); 移动到控制器的操作上,一切正常。

【讨论】:

以上是关于如何使用 ActionCable 在 Rails( api-only ) 应用程序中主动发送消息?的主要内容,如果未能解决你的问题,请参考以下文章

如何将消息发送给除 rails/actioncable 中的发件人之外的所有客户端?

Rails 4 和 ActionCable

如何在生产中使用 Nginx 和 Unicorn 配置 ActionCable?

在 Rails 中的控制台无法使用 Actioncable 广播

如何在 ActionCable rails-5-api 应用程序中获取 current_user?

如何使用 ActionCable 作为 API