【问题标题】:How to send message proactively in Rails( api-only ) Apps using ActionCable?如何使用 ActionCable 在 Rails( api-only ) 应用程序中主动发送消息?
【发布时间】:2019-12-20 03:51:19
【问题描述】:

说明

项目结构:

  • 一个基于 Vue 的 FE 项目。
  • 后端的 Rails( api-only ) 项目。 ruby263@rails517

要求:

  1. FE打开一个websocket链接,使用参数{ weigh_device_id : 1}订阅。
  2. BE 确认订阅。
  3. 通过 weight_device_id 查找设备。
  4. 当客户端调用“WeighDevice#sync_reading”时,BE立即发送设备读数。
  5. 当设备读数更新时,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;
    }
});



所以,这里有问题。

  1. broadcast_tobroadcast 有什么区别?
  2. broadcast_tobroadcast 接受不同的参数并在不同的字段中可用。也就是说,我只能在WeighDeviceChannel#action 中使用broadcast,但不能在其中使用。我只能使用broadcast_to out of WeighDeviceChannel#action 但不能在其中使用。
  3. 为什么我在客户端收不到任何东西?我的演示有什么问题?

【问题讨论】:

  • 什么是 FE 或 BE?
  • 对不起,我没有描述清楚。这是前端和后端。

标签: ruby-on-rails websocket actioncable


【解决方案1】:

我明白发生了什么。

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

【讨论】:

    猜你喜欢
    • 2017-07-16
    • 2014-10-17
    • 2014-03-04
    • 2019-04-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多