Rails API 使用 ActionCable (WS) 和 React 前端
Rails API with ActionCable (WS) and React Front End
我已经通过 ActionCable 为我的 Rails API/React 前端应用程序设置了 WebSockets,但我正在努力使用一些非常奇怪的功能。目前,我的 <ActionCableConsumer />
正在随机射击。假设我打开了四个浏览器,我提交了一个应该向所有四个浏览器呈现新数据的表单,其中两个可以从通道流式传输数据,而另外两个不呈现任何内容。或者其中一个浏览器可能多次呈现数据,而其他三个浏览器什么也不呈现。这确实是零星交易。
这是我从订阅中获取数据并更新状态的地方:
handleReceived = (message) => {
console.log('check me')
this.setState({
apiData: [...this.state.apiData, message.pickup_delivery]
});
}
render(){
return(
<div>
<ActionCableConsumer channel={{channel: 'PickupDeliveriesChannel'}} onReceived={this.handleReceived}>
<div>
<CustomersForm showCustForm={this.state.showCustForm} handleClose={this.hideForm} addNewCustomer={this.addNewCustomer} />
<Calendar getCustForm={this.getCustForm} getForm={this.getForm} deleteLoad={this.deleteLoad} {...this.state} seededColorGenerator={this.seededColorGenerator} />
<PickupDeliveriesForm getFormColor={this.getFormColor} deleteCustomer={this.deleteCustomer} handleClose={this.hideForm} showForm={this.state.showForm} updateLoad={this.updateLoad} {...this.state} onNewLoad={this.addNewLoad} seededColorGenerator={this.seededColorGenerator} />
</div>
</ActionCableConsumer>
</div>
)
}
}
这是我的控制器的样子:
module Api::V1
class PickupDeliveriesController < ApplicationController
before_action :set_pickup_delivery, only: [:show, :update, :destroy]
# GET /pickup_deliveries
def index
@pickup_deliveries = PickupDelivery.all
render json: @pickup_deliveries
end
# GET /pickup_deliveries/1
def show
render json: @pickup_delivery
end
# POST /pickup_deliveriesPickupDeliveries
def create
pickup_deliveries = PickupDelivery.new(pickup_delivery_params)
if pickup_deliveries.save
serialized_data = ActiveModelSerializers::Adapter::Json.new(
PickupDeliveriesSerializer.new(pickup_deliveries)
).serializable_hash
ActionCable.server.broadcast 'pickup_deliveries_channel', serialized_data
head :ok
end
end
# PATCH/PUT /pickup_deliveries/1
def update
if @pickup_delivery.update(pickup_delivery_params)
render json: @pickup_delivery
else
render json: @pickup_delivery.errors, status: :unprocessable_entity
end
end
# DELETE /pickup_deliveries/1
def destroy
@pickup_delivery.destroy
end
private
# Use callbacks to share common setup or constraints between actions.
def set_pickup_delivery
@pickup_delivery = PickupDelivery.find(params[:id])
end
# Only allow a trusted parameter "white list" through.
def pickup_delivery_params
params.require(:pickup_delivery).permit(:id, :pickup_date, :pickup_location, :rate, :delivery_date, :delivery_location, :local_delivery, :local_pickup, :loaded_miles, :deadhead_miles, :delivery_id, :pickup_zip, :delivery_zip, :hazmat, :sameday, :delivery_time, :pickup_time, :aurora_number, :out_of_route, :round_trip, :customer_id, :color)
end
end
end
这是我的真实频道:
class PickupDeliveriesChannel < ApplicationCable::Channel
def subscribed
stream_from 'pickup_deliveries_channel'
end
end
我没有指定任何用户,因为我还不需要。基本上,当客户端在负载板上提交新负载时,我需要所有其他负载板来显示新实例。目前,它并没有像那样工作。
打开五个浏览器并在随机浏览器上提交一个表单后,五个浏览器中的三个呈现正确的数据(一次加载),一个浏览器不呈现任何内容,一个浏览器呈现数据两次。
这是纯粹的混乱哈哈。
PickupDeliveriesChannel transmitting {"pickup_delivery"=>{"id"=>17, "pickup_date"=>"2019-11-16", "pickup_location"=>"", "rate"=>nil, "delivery_date"=>"2019-11-16", "delivery_location"=>"", "local_delivery"=>false, "local_pickup"=>false, "loaded_miles"=>nil, "deadhead_miles"=>nil, "delivery_id"=>nil, "pickup_zip"=>"", "delivery_zip"=... (via streamed from pickup_deliveries_channel)
PickupDeliveriesChannel transmitting {"pickup_delivery"=>{"id"=>17, "pickup_date"=>"2019-11-16", "pickup_location"=>"", "rate"=>nil, "delivery_date"=>"2019-11-16", "delivery_location"=>"", "local_delivery"=>false, "local_pickup"=>false, "loaded_miles"=>nil, "deadhead_miles"=>nil, "delivery_id"=>nil, "pickup_zip"=>"", "delivery_zip"=... (via streamed from pickup_deliveries_channel)
PickupDeliveriesChannel transmitting {"pickup_delivery"=>{"id"=>17, "pickup_date"=>"2019-11-16", "pickup_location"=>"", "rate"=>nil, "delivery_date"=>"2019-11-16", "delivery_location"=>"", "local_delivery"=>false, "local_pickup"=>false, "loaded_miles"=>nil, "deadhead_miles"=>nil, "delivery_id"=>nil, "pickup_zip"=>"", "delivery_zip"=... (via streamed from pickup_deliveries_channel)
PickupDeliveriesChannel transmitting {"pickup_delivery"=>{"id"=>17, "pickup_date"=>"2019-11-16", "pickup_location"=>"", "rate"=>nil, "delivery_date"=>"2019-11-16", "delivery_location"=>"", "local_delivery"=>false, "local_pickup"=>false, "loaded_miles"=>nil, "deadhead_miles"=>nil, "delivery_id"=>nil, "pickup_zip"=>"", "delivery_zip"=... (via streamed from pickup_deliveries_channel)
PickupDeliveriesChannel transmitting {"pickup_delivery"=>{"id"=>17, "pickup_date"=>"2019-11-16", "pickup_location"=>"", "rate"=>nil, "delivery_date"=>"2019-11-16", "delivery_location"=>"", "local_delivery"=>false, "local_pickup"=>false, "loaded_miles"=>nil, "deadhead_miles"=>nil, "delivery_id"=>nil, "pickup_zip"=>"", "delivery_zip"=... (via streamed from pickup_deliveries_channel)
PickupDeliveriesChannel transmitting {"pickup_delivery"=>{"id"=>17, "pickup_date"=>"2019-11-16", "pickup_location"=>"", "rate"=>nil, "delivery_date"=>"2019-11-16", "delivery_location"=>"", "local_delivery"=>false, "local_pickup"=>false, "loaded_miles"=>nil, "deadhead_miles"=>nil, "delivery_id"=>nil, "pickup_zip"=>"", "delivery_zip"=... (via streamed from pickup_deliveries_channel)
PickupDeliveriesChannel transmitting {"pickup_delivery"=>{"id"=>17, "pickup_date"=>"2019-11-16", "pickup_location"=>"", "rate"=>nil, "delivery_date"=>"2019-11-16", "delivery_location"=>"", "local_delivery"=>false, "local_pickup"=>false, "loaded_miles"=>nil, "deadhead_miles"=>nil, "delivery_id"=>nil, "pickup_zip"=>"", "delivery_zip"=... (via streamed from pickup_deliveries_channel)
PickupDeliveriesChannel transmitting {"pickup_delivery"=>{"id"=>17, "pickup_date"=>"2019-11-16", "pickup_location"=>"", "rate"=>nil, "delivery_date"=>"2019-11-16", "delivery_location"=>"", "local_delivery"=>false, "local_pickup"=>false, "loaded_miles"=>nil, "deadhead_miles"=>nil, "delivery_id"=>nil, "pickup_zip"=>"", "delivery_zip"=... (via streamed from pickup_deliveries_channel)
PickupDeliveriesChannel transmitting {"pickup_delivery"=>{"id"=>17, "pickup_date"=>"2019-11-16", "pickup_location"=>"", "rate"=>nil, "delivery_date"=>"2019-11-16", "delivery_location"=>"", "local_delivery"=>false, "local_pickup"=>false, "loaded_miles"=>nil, "deadhead_miles"=>nil, "delivery_id"=>nil, "pickup_zip"=>"", "delivery_zip"=... (via streamed from pickup_deliveries_channel)
PickupDeliveriesChannel transmitting {"pickup_delivery"=>{"id"=>17, "pickup_date"=>"2019-11-16", "pickup_location"=>"", "rate"=>nil, "delivery_date"=>"2019-11-16", "delivery_location"=>"", "local_delivery"=>false, "local_pickup"=>false, "loaded_miles"=>nil, "deadhead_miles"=>nil, "delivery_id"=>nil, "pickup_zip"=>"", "delivery_zip"=... (via streamed from pickup_deliveries_channel)
PickupDeliveriesChannel transmitting {"pickup_delivery"=>{"id"=>17, "pickup_date"=>"2019-11-16", "pickup_location"=>"", "rate"=>nil, "delivery_date"=>"2019-11-16", "delivery_location"=>"", "local_delivery"=>false, "local_pickup"=>false, "loaded_miles"=>nil, "deadhead_miles"=>nil, "delivery_id"=>nil, "pickup_zip"=>"", "delivery_zip"=... (via streamed from pickup_deliveries_channel)
PickupDeliveriesChannel transmitting {"pickup_delivery"=>{"id"=>17, "pickup_date"=>"2019-11-16", "pickup_location"=>"", "rate"=>nil, "delivery_date"=>"2019-11-16", "delivery_location"=>"", "local_delivery"=>false, "local_pickup"=>false, "loaded_miles"=>nil, "deadhead_miles"=>nil, "delivery_id"=>nil, "pickup_zip"=>"", "delivery_zip"=... (via streamed from pickup_deliveries_channel)
PickupDeliveriesChannel transmitting {"pickup_delivery"=>{"id"=>17, "pickup_date"=>"2019-11-16", "pickup_location"=>"", "rate"=>nil, "delivery_date"=>"2019-11-16", "delivery_location"=>"", "local_delivery"=>false, "local_pickup"=>false, "loaded_miles"=>nil, "deadhead_miles"=>nil, "delivery_id"=>nil, "pickup_zip"=>"", "delivery_zip"=... (via streamed from pickup_deliveries_channel)
Unsubscribing from channel: {"channel":"PickupDeliveriesChannel"}
PickupDeliveriesChannel is transmitting the subscription confirmation
PickupDeliveriesChannel is streaming from pickup_deliveries_channel
PickupDeliveriesChannel stopped streaming from pickup_deliveries_channel
Unsubscribing from channel: {"channel":"PickupDeliveriesChannel"}
PickupDeliveriesChannel is transmitting the subscription confirmation
PickupDeliveriesChannel is streaming from pickup_deliveries_channel
PickupDeliveriesChannel stopped streaming from pickup_deliveries_channel
Unsubscribing from channel: {"channel":"PickupDeliveriesChannel"}
Unsubscribing from channel: {"channel":"PickupDeliveriesChannel"}
PickupDeliveriesChannel stopped streaming from pickup_deliveries_channel
PickupDeliveriesChannel stopped streaming from pickup_deliveries_channel
Unsubscribing from channel: {"channel":"PickupDeliveriesChannel"}
Could not execute command from ({"command"=>"unsubscribe", "identifier"=>"{\"channel\":\"PickupDeliveriesChannel\"}"}) [RuntimeError - Unable to find subscription with identifier: {"channel":"PickupDeliveriesChannel"}]: C:/Ruby26-x64/lib/ruby/gems/2.6.0/gems/actioncable-5.2.3/lib/action_cable/connection/subscriptions.rb:78:in `find' | C:/Ruby26-x64/lib/ruby/gems/2.6.0/gems/actioncable-5.2.3/lib/action_cable/connection/subscriptions.rb:46:in `remove' | C:/Ruby26-x64/lib/ruby/gems/2.6.0/gems/actioncable-5.2.3/lib/action_cable/connection/subscriptions.rb:18:in `execute_command' | C:/Ruby26-x64/lib/ruby/gems/2.6.0/gems/actioncable-5.2.3/lib/action_cable/connection/base.rb:87:in `dispatch_websocket_message' | C:/Ruby26-x64/lib/ruby/gems/2.6.0/gems/actioncable-5.2.3/lib/action_cable/server/worker.rb:60:in `block in invoke'
PickupDeliveriesChannel is transmitting the subscription confirmation
PickupDeliveriesChannel is streaming from pickup_deliveries_channel
Unsubscribing from channel: {"channel":"PickupDeliveriesChannel"}
PickupDeliveriesChannel stopped streaming from pickup_deliveries_channel
PickupDeliveriesChannel is transmitting the subscription confirmation
PickupDeliveriesChannel is streaming from pickup_deliveries_channel
在那个特定的提交上,这是我的 rails 控制台的样子。
这是纯粹的混乱,我不知道如何让它正确流动。
编辑:
我提交的表单越多,打开的订阅就越多。这几乎就像每次我打开表单提交东西时,另一个订阅正在流式传输?打开两个浏览器,我可以传输任意数量的对象...
这是我的路线:
Rails.application.routes.draw do
namespace :api do
namespace :v1 do
resources :pickup_deliveries
resources :customers
end
end
mount ActionCable.server => '/cable'
end
这是我的 index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { ActionCableProvider } from 'react-actioncable-provider';
import * as serviceWorker from './serviceWorker';
import { API_WS_ROOT } from './constants';
ReactDOM.render(
<ActionCableProvider url={API_WS_ROOT}>
<App />
</ActionCableProvider>,
document.getElementById('root')
);
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
serviceWorker.unregister();
这是我正在使用的常量
export const API_ROOT = 'http://localhost:3001/api/v1';
export const API_WS_ROOT = 'ws://localhost:3001/cable';
export const HEADERS = {
'Content-Type': 'application/json',
Accept: 'application/json',
};
websocket 支持每个应用程序实例一个连接,一个服务器一个客户端。更新不是随机的,它会转到最后一个打开了与 websocket 的连接的应用程序。
所以,我想通了。我将包含我所有获取实例的当前状态从前端 VIA params
发送到通道,并将其与当前数据库进行比较。老实说,我不太确定它为什么起作用。基本上,我说如果 params[:all_loads]
(前端当前获取的响应)等于后端对象中的实例数量,则继续流式传输到通道。解决方案如下:
class PickupDeliveriesChannel < ApplicationCable::Channel
def subscribed
if params[:all_loads].length == PickupDelivery.all.length
stream_from 'pickup_deliveries_channel'
end
end
def unsubscribed
end
end
我已经通过 ActionCable 为我的 Rails API/React 前端应用程序设置了 WebSockets,但我正在努力使用一些非常奇怪的功能。目前,我的 <ActionCableConsumer />
正在随机射击。假设我打开了四个浏览器,我提交了一个应该向所有四个浏览器呈现新数据的表单,其中两个可以从通道流式传输数据,而另外两个不呈现任何内容。或者其中一个浏览器可能多次呈现数据,而其他三个浏览器什么也不呈现。这确实是零星交易。
这是我从订阅中获取数据并更新状态的地方:
handleReceived = (message) => {
console.log('check me')
this.setState({
apiData: [...this.state.apiData, message.pickup_delivery]
});
}
render(){
return(
<div>
<ActionCableConsumer channel={{channel: 'PickupDeliveriesChannel'}} onReceived={this.handleReceived}>
<div>
<CustomersForm showCustForm={this.state.showCustForm} handleClose={this.hideForm} addNewCustomer={this.addNewCustomer} />
<Calendar getCustForm={this.getCustForm} getForm={this.getForm} deleteLoad={this.deleteLoad} {...this.state} seededColorGenerator={this.seededColorGenerator} />
<PickupDeliveriesForm getFormColor={this.getFormColor} deleteCustomer={this.deleteCustomer} handleClose={this.hideForm} showForm={this.state.showForm} updateLoad={this.updateLoad} {...this.state} onNewLoad={this.addNewLoad} seededColorGenerator={this.seededColorGenerator} />
</div>
</ActionCableConsumer>
</div>
)
}
}
这是我的控制器的样子:
module Api::V1
class PickupDeliveriesController < ApplicationController
before_action :set_pickup_delivery, only: [:show, :update, :destroy]
# GET /pickup_deliveries
def index
@pickup_deliveries = PickupDelivery.all
render json: @pickup_deliveries
end
# GET /pickup_deliveries/1
def show
render json: @pickup_delivery
end
# POST /pickup_deliveriesPickupDeliveries
def create
pickup_deliveries = PickupDelivery.new(pickup_delivery_params)
if pickup_deliveries.save
serialized_data = ActiveModelSerializers::Adapter::Json.new(
PickupDeliveriesSerializer.new(pickup_deliveries)
).serializable_hash
ActionCable.server.broadcast 'pickup_deliveries_channel', serialized_data
head :ok
end
end
# PATCH/PUT /pickup_deliveries/1
def update
if @pickup_delivery.update(pickup_delivery_params)
render json: @pickup_delivery
else
render json: @pickup_delivery.errors, status: :unprocessable_entity
end
end
# DELETE /pickup_deliveries/1
def destroy
@pickup_delivery.destroy
end
private
# Use callbacks to share common setup or constraints between actions.
def set_pickup_delivery
@pickup_delivery = PickupDelivery.find(params[:id])
end
# Only allow a trusted parameter "white list" through.
def pickup_delivery_params
params.require(:pickup_delivery).permit(:id, :pickup_date, :pickup_location, :rate, :delivery_date, :delivery_location, :local_delivery, :local_pickup, :loaded_miles, :deadhead_miles, :delivery_id, :pickup_zip, :delivery_zip, :hazmat, :sameday, :delivery_time, :pickup_time, :aurora_number, :out_of_route, :round_trip, :customer_id, :color)
end
end
end
这是我的真实频道:
class PickupDeliveriesChannel < ApplicationCable::Channel
def subscribed
stream_from 'pickup_deliveries_channel'
end
end
我没有指定任何用户,因为我还不需要。基本上,当客户端在负载板上提交新负载时,我需要所有其他负载板来显示新实例。目前,它并没有像那样工作。
打开五个浏览器并在随机浏览器上提交一个表单后,五个浏览器中的三个呈现正确的数据(一次加载),一个浏览器不呈现任何内容,一个浏览器呈现数据两次。
这是纯粹的混乱哈哈。
PickupDeliveriesChannel transmitting {"pickup_delivery"=>{"id"=>17, "pickup_date"=>"2019-11-16", "pickup_location"=>"", "rate"=>nil, "delivery_date"=>"2019-11-16", "delivery_location"=>"", "local_delivery"=>false, "local_pickup"=>false, "loaded_miles"=>nil, "deadhead_miles"=>nil, "delivery_id"=>nil, "pickup_zip"=>"", "delivery_zip"=... (via streamed from pickup_deliveries_channel)
PickupDeliveriesChannel transmitting {"pickup_delivery"=>{"id"=>17, "pickup_date"=>"2019-11-16", "pickup_location"=>"", "rate"=>nil, "delivery_date"=>"2019-11-16", "delivery_location"=>"", "local_delivery"=>false, "local_pickup"=>false, "loaded_miles"=>nil, "deadhead_miles"=>nil, "delivery_id"=>nil, "pickup_zip"=>"", "delivery_zip"=... (via streamed from pickup_deliveries_channel)
PickupDeliveriesChannel transmitting {"pickup_delivery"=>{"id"=>17, "pickup_date"=>"2019-11-16", "pickup_location"=>"", "rate"=>nil, "delivery_date"=>"2019-11-16", "delivery_location"=>"", "local_delivery"=>false, "local_pickup"=>false, "loaded_miles"=>nil, "deadhead_miles"=>nil, "delivery_id"=>nil, "pickup_zip"=>"", "delivery_zip"=... (via streamed from pickup_deliveries_channel)
PickupDeliveriesChannel transmitting {"pickup_delivery"=>{"id"=>17, "pickup_date"=>"2019-11-16", "pickup_location"=>"", "rate"=>nil, "delivery_date"=>"2019-11-16", "delivery_location"=>"", "local_delivery"=>false, "local_pickup"=>false, "loaded_miles"=>nil, "deadhead_miles"=>nil, "delivery_id"=>nil, "pickup_zip"=>"", "delivery_zip"=... (via streamed from pickup_deliveries_channel)
PickupDeliveriesChannel transmitting {"pickup_delivery"=>{"id"=>17, "pickup_date"=>"2019-11-16", "pickup_location"=>"", "rate"=>nil, "delivery_date"=>"2019-11-16", "delivery_location"=>"", "local_delivery"=>false, "local_pickup"=>false, "loaded_miles"=>nil, "deadhead_miles"=>nil, "delivery_id"=>nil, "pickup_zip"=>"", "delivery_zip"=... (via streamed from pickup_deliveries_channel)
PickupDeliveriesChannel transmitting {"pickup_delivery"=>{"id"=>17, "pickup_date"=>"2019-11-16", "pickup_location"=>"", "rate"=>nil, "delivery_date"=>"2019-11-16", "delivery_location"=>"", "local_delivery"=>false, "local_pickup"=>false, "loaded_miles"=>nil, "deadhead_miles"=>nil, "delivery_id"=>nil, "pickup_zip"=>"", "delivery_zip"=... (via streamed from pickup_deliveries_channel)
PickupDeliveriesChannel transmitting {"pickup_delivery"=>{"id"=>17, "pickup_date"=>"2019-11-16", "pickup_location"=>"", "rate"=>nil, "delivery_date"=>"2019-11-16", "delivery_location"=>"", "local_delivery"=>false, "local_pickup"=>false, "loaded_miles"=>nil, "deadhead_miles"=>nil, "delivery_id"=>nil, "pickup_zip"=>"", "delivery_zip"=... (via streamed from pickup_deliveries_channel)
PickupDeliveriesChannel transmitting {"pickup_delivery"=>{"id"=>17, "pickup_date"=>"2019-11-16", "pickup_location"=>"", "rate"=>nil, "delivery_date"=>"2019-11-16", "delivery_location"=>"", "local_delivery"=>false, "local_pickup"=>false, "loaded_miles"=>nil, "deadhead_miles"=>nil, "delivery_id"=>nil, "pickup_zip"=>"", "delivery_zip"=... (via streamed from pickup_deliveries_channel)
PickupDeliveriesChannel transmitting {"pickup_delivery"=>{"id"=>17, "pickup_date"=>"2019-11-16", "pickup_location"=>"", "rate"=>nil, "delivery_date"=>"2019-11-16", "delivery_location"=>"", "local_delivery"=>false, "local_pickup"=>false, "loaded_miles"=>nil, "deadhead_miles"=>nil, "delivery_id"=>nil, "pickup_zip"=>"", "delivery_zip"=... (via streamed from pickup_deliveries_channel)
PickupDeliveriesChannel transmitting {"pickup_delivery"=>{"id"=>17, "pickup_date"=>"2019-11-16", "pickup_location"=>"", "rate"=>nil, "delivery_date"=>"2019-11-16", "delivery_location"=>"", "local_delivery"=>false, "local_pickup"=>false, "loaded_miles"=>nil, "deadhead_miles"=>nil, "delivery_id"=>nil, "pickup_zip"=>"", "delivery_zip"=... (via streamed from pickup_deliveries_channel)
PickupDeliveriesChannel transmitting {"pickup_delivery"=>{"id"=>17, "pickup_date"=>"2019-11-16", "pickup_location"=>"", "rate"=>nil, "delivery_date"=>"2019-11-16", "delivery_location"=>"", "local_delivery"=>false, "local_pickup"=>false, "loaded_miles"=>nil, "deadhead_miles"=>nil, "delivery_id"=>nil, "pickup_zip"=>"", "delivery_zip"=... (via streamed from pickup_deliveries_channel)
PickupDeliveriesChannel transmitting {"pickup_delivery"=>{"id"=>17, "pickup_date"=>"2019-11-16", "pickup_location"=>"", "rate"=>nil, "delivery_date"=>"2019-11-16", "delivery_location"=>"", "local_delivery"=>false, "local_pickup"=>false, "loaded_miles"=>nil, "deadhead_miles"=>nil, "delivery_id"=>nil, "pickup_zip"=>"", "delivery_zip"=... (via streamed from pickup_deliveries_channel)
PickupDeliveriesChannel transmitting {"pickup_delivery"=>{"id"=>17, "pickup_date"=>"2019-11-16", "pickup_location"=>"", "rate"=>nil, "delivery_date"=>"2019-11-16", "delivery_location"=>"", "local_delivery"=>false, "local_pickup"=>false, "loaded_miles"=>nil, "deadhead_miles"=>nil, "delivery_id"=>nil, "pickup_zip"=>"", "delivery_zip"=... (via streamed from pickup_deliveries_channel)
Unsubscribing from channel: {"channel":"PickupDeliveriesChannel"}
PickupDeliveriesChannel is transmitting the subscription confirmation
PickupDeliveriesChannel is streaming from pickup_deliveries_channel
PickupDeliveriesChannel stopped streaming from pickup_deliveries_channel
Unsubscribing from channel: {"channel":"PickupDeliveriesChannel"}
PickupDeliveriesChannel is transmitting the subscription confirmation
PickupDeliveriesChannel is streaming from pickup_deliveries_channel
PickupDeliveriesChannel stopped streaming from pickup_deliveries_channel
Unsubscribing from channel: {"channel":"PickupDeliveriesChannel"}
Unsubscribing from channel: {"channel":"PickupDeliveriesChannel"}
PickupDeliveriesChannel stopped streaming from pickup_deliveries_channel
PickupDeliveriesChannel stopped streaming from pickup_deliveries_channel
Unsubscribing from channel: {"channel":"PickupDeliveriesChannel"}
Could not execute command from ({"command"=>"unsubscribe", "identifier"=>"{\"channel\":\"PickupDeliveriesChannel\"}"}) [RuntimeError - Unable to find subscription with identifier: {"channel":"PickupDeliveriesChannel"}]: C:/Ruby26-x64/lib/ruby/gems/2.6.0/gems/actioncable-5.2.3/lib/action_cable/connection/subscriptions.rb:78:in `find' | C:/Ruby26-x64/lib/ruby/gems/2.6.0/gems/actioncable-5.2.3/lib/action_cable/connection/subscriptions.rb:46:in `remove' | C:/Ruby26-x64/lib/ruby/gems/2.6.0/gems/actioncable-5.2.3/lib/action_cable/connection/subscriptions.rb:18:in `execute_command' | C:/Ruby26-x64/lib/ruby/gems/2.6.0/gems/actioncable-5.2.3/lib/action_cable/connection/base.rb:87:in `dispatch_websocket_message' | C:/Ruby26-x64/lib/ruby/gems/2.6.0/gems/actioncable-5.2.3/lib/action_cable/server/worker.rb:60:in `block in invoke'
PickupDeliveriesChannel is transmitting the subscription confirmation
PickupDeliveriesChannel is streaming from pickup_deliveries_channel
Unsubscribing from channel: {"channel":"PickupDeliveriesChannel"}
PickupDeliveriesChannel stopped streaming from pickup_deliveries_channel
PickupDeliveriesChannel is transmitting the subscription confirmation
PickupDeliveriesChannel is streaming from pickup_deliveries_channel
在那个特定的提交上,这是我的 rails 控制台的样子。
这是纯粹的混乱,我不知道如何让它正确流动。
编辑: 我提交的表单越多,打开的订阅就越多。这几乎就像每次我打开表单提交东西时,另一个订阅正在流式传输?打开两个浏览器,我可以传输任意数量的对象...
这是我的路线:
Rails.application.routes.draw do
namespace :api do
namespace :v1 do
resources :pickup_deliveries
resources :customers
end
end
mount ActionCable.server => '/cable'
end
这是我的 index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { ActionCableProvider } from 'react-actioncable-provider';
import * as serviceWorker from './serviceWorker';
import { API_WS_ROOT } from './constants';
ReactDOM.render(
<ActionCableProvider url={API_WS_ROOT}>
<App />
</ActionCableProvider>,
document.getElementById('root')
);
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
serviceWorker.unregister();
这是我正在使用的常量
export const API_ROOT = 'http://localhost:3001/api/v1';
export const API_WS_ROOT = 'ws://localhost:3001/cable';
export const HEADERS = {
'Content-Type': 'application/json',
Accept: 'application/json',
};
websocket 支持每个应用程序实例一个连接,一个服务器一个客户端。更新不是随机的,它会转到最后一个打开了与 websocket 的连接的应用程序。
所以,我想通了。我将包含我所有获取实例的当前状态从前端 VIA params
发送到通道,并将其与当前数据库进行比较。老实说,我不太确定它为什么起作用。基本上,我说如果 params[:all_loads]
(前端当前获取的响应)等于后端对象中的实例数量,则继续流式传输到通道。解决方案如下:
class PickupDeliveriesChannel < ApplicationCable::Channel
def subscribed
if params[:all_loads].length == PickupDelivery.all.length
stream_from 'pickup_deliveries_channel'
end
end
def unsubscribed
end
end