в rails с action cable невозможно отправить с клиента на сервер

#ruby-on-rails #actioncable

#ruby-on-rails #actioncable

Вопрос:

в rails с action cable я не могу получить сообщение от клиента к серверу, хотя я могу отправить с сервера на канал клиенту.

Вы можете увидеть все файлы здесь, и в конце я показал их с помощью cat, поскольку я показываю все команды, используемые при создании программы

Глядя в awpchan_channel.rb, у меня есть подписка на def, которая работает, команда puts там будет записываться на сервер. Но def receive (data) никогда не запускается. Я написал туда puts, и он не выполняется.

Но у меня есть строка в файле js, которая предназначена для отправки строки с клиента на сервер. App.awpchan.send('This is a cool chat app.'); Но он этого не делает.

У меня это было в coffeescript, но это тоже не помогло.

config/routes.rb

 Rails.application.routes.draw do

mount ActionCable.server, at: '/cable'

root 'application#index'

end
  

app /controllers/application_controller.rb

 class ApplicationController < ActionController::Base
 def index
   ActionCable.server.broadcast 'abcdstrm', 'zzz'  
 end
end
  

app/channels/awpchan_channel.rb

 class AwpchanChannel < ApplicationCable::Channel
  def subscribed
    stream_from "abcdstrm"
  end

  def unsubscribed
    # Any cleanup needed when channel is unsubscribed
  end

  def receive(data)
   puts "RECEIVE BY SERVER"
  end

end
  

app /assets/ javascripts / channels/awpchan.coffee (я переименовал имя файла и расширение в oldawpchan.oldcoffee, поскольку я его не использую, использую theawpchan.js вместо этого)

 App.awpchan = App.cable.subscriptions.create "AwpchanChannel",
  connected: ->
    # Called when the subscription is ready for use on the server

  disconnected: ->
    # Called when the subscription has been terminated by the server

  received: (data) ->
    # Called when there's incoming data on the websocket for this channel
    alert(data)

App.awpchan.send 'This is a cool chat app.'
  

app/assets/javascripts/theawpchan.js

 App.awpchan = App.cable.subscriptions.create("AwpchanChannel", {
  connected: function() {},
  disconnected: function() {},
  received: function(data) {
    return alert(data);
  }
});

App.awpchan.send('This is a cool chat app.');

// http://js2.coffee/
  

app/views/application/index.html.erb (который пуст)

Вот как я создал программу

 ~/rubymac$ cd channeltests
~/rubymac/channeltests$ mkdir channeltest1
~/rubymac/channeltests$ cd channeltest1
~/rubymac/channeltests/channeltest1$ rails new . >nul
~/rubymac/channeltests/channeltest1$ vi config/routes.rb 
~/rubymac/channeltests/channeltest1$ cat config/routes.rb 
Rails.application.routes.draw do

mount ActionCable.server, at: '/cable'

root 'application#index'

end
~/rubymac/channeltests/channeltest1$ mkdir app/views/application
~/rubymac/channeltests/channeltest1$ touch app/views/application/index.html.erb
~/rubymac/channeltests/channeltest1$ vi app/controllers/application_controller.rb 
~/rubymac/channeltests/channeltest1$ cat app/controllers/application_controller.rb 
class ApplicationController < ActionController::Base
def index
ActionCable.server.broadcast 'abcdstrm', 'zzz'  
end
end
~/rubymac/channeltests/channeltest1$ rails generate channel awpchan
Running via Spring preloader in process 4020
      create  app/channels/awpchan_channel.rb
   identical  app/assets/javascripts/cable.js
      create  app/assets/javascripts/channels/awpchan.coffee
~/rubymac/channeltests/channeltest1$ vi app/channels/awpchan_channel.rb
~/rubymac/channeltests/channeltest1$ cat app/channels/awpchan_channel.rb 
class AwpchanChannel < ApplicationCable::Channel
  def subscribed
    stream_from "abcdstrm"
  end

  def unsubscribed
    # Any cleanup needed when channel is unsubscribed
  end

  def receive(data)  
   puts "RECEIVE BY SERVER"
  end

end
~/rubymac/channeltests/channeltest1$ vi app/assets/javascripts/channels/awpchan.coffee 
~/rubymac/channeltests/channeltest1$ cat app/assets/javascripts/channels/awpchan.coffee 
App.awpchan = App.cable.subscriptions.create "AwpchanChannel",
  connected: ->
    # Called when the subscription is ready for use on the server

  disconnected: ->
    # Called when the subscription has been terminated by the server

  received: (data) ->
    # Called when there's incoming data on the websocket for this channel
    alert(data)

App.awpchan.send 'This is a cool chat app.'
~/rubymac/channeltests/channeltest1$ cd app/assets/javascripts/channels/
~/rubymac/channeltests/channeltest1/app/assets/javascripts/channels$ mv awpchan.coffee oldawpchan.oldcoffee
~/rubymac/channeltests/channeltest1/app/assets/javascripts/channels$ vi oldawpchan.oldcoffee 
~/rubymac/channeltests/channeltest1/app/assets/javascripts/channels$ vi theawpchan.js
~/rubymac/channeltests/channeltest1/app/assets/javascripts/channels$ cat theawpchan.js 
App.awpchan = App.cable.subscriptions.create("AwpchanChannel", {
  connected: function() {},
  disconnected: function() {},
  received: function(data) {
    return alert(data);
  }
});

App.awpchan.send('This is a cool chat app.');

// http://js2.coffee/
~/rubymac/channeltests/channeltest1/app/assets/javascripts/channels$ cd ../../../
~/rubymac/channeltests/channeltest1/app$ cd ..


~/rubymac/channeltests/channeltest1$ rails s
=> Booting Puma
=> Rails 5.2.3 application starting in development 
=> Run `rails server -h` for more startup options
Puma starting in single mode...
* Version 3.12.1 (ruby 2.5.0-p0), codename: Llamas in Pajamas
* Min threads: 5, max threads: 5
* Environment: development
* Listening on tcp://localhost:3000
Use Ctrl-C to stop
Started GET "/" for 127.0.0.1 at 2019-04-21 23:40:55  0100
Processing by ApplicationController#index as HTML
[ActionCable] Broadcasting to abcdstrm: "zzz"
  Rendering application/index.html.erb within layouts/application
  Rendered application/index.html.erb within layouts/application (1.5ms)
Completed 200 OK in 469ms (Views: 430.1ms | ActiveRecord: 0.0ms)


Started GET "/cable" for 127.0.0.1 at 2019-04-21 23:41:25  0100
Started GET "/cable/" [WebSocket] for 127.0.0.1 at 2019-04-21 23:41:25  0100
Successfully upgraded to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: Upgrade, HTTP_UPGRADE: websocket)
AwpchanChannel is transmitting the subscription confirmation
AwpchanChannel is streaming from abcdstrm
  

добавлено

Применяя предложение arieljuod, в файле js помещаем строку отправки в тело метода connect. Чтобы он не отправлял слишком рано.

Это улучшает ситуацию, теперь я получаю это сообщение

сразу после того, как сервер скажет

 AwpchanChannel is transmitting the subscription confirmation
AwpchanChannel is streaming from abcdstrm
  

теперь это выдает эту ошибку (это будет при выполнении команды отправки)

 Could not execute command from ({"command"=>"message", "identifier"=>"{"channel":"AwpchanChannel"}", "data"=>""This is a cool chat app.""}) [NoMethodError - undefined method `except' for "This is a cool chat app.":String]: /usr/local/lib/ruby/gems/2.5.0/gems/actionc...
  

Комментарии:

1. Я не уверен, но, возможно, вы отправляете сообщение до того, как канал будет правильно подключен (сначала вам следует дождаться connected обратного вызова). Что произойдет, если вы переместите эту App.awpchan.send('This is a cool chat app.'); строку внутри функции connected обратного вызова?

2. @arieljuod спасибо, это улучшает ситуацию, я включил ошибку, которую получаю сейчас. Я нашел два результата поиска по нему, но я не уверен, как они связаны с моей проблемой

3. Я думаю, вам нужно определить имя переменной, которую вы отправляете, чтобы вы могли правильно идентифицировать ее на сервере. Что-то вроде: send({message: 'This is a cool chat app.'}) .

4. @arieljuod спасибо, вы были правы.. Я вижу, что это должен быть хэш при отправке клиента на сервер. например App.awpchan.send({aa:'rrrrr'}); . или ...send({message: 'This is a cool chat app.'}) . и теперь нет сбоя. Можете ли вы опубликовать ответ, включающий оба этих решения: А) ввод строки в соединение Б) передача хэша. затем выполняется def received, sorted (и тогда в def received я могу сделать, например puts data["message"] . great. ) Итак, были две вещи, которые я делал неправильно, что привело к тому, что он не попал def received . Можете ли вы опубликовать ответ с упоминанием об этом, и я приму его. Спасибо

Ответ №1:

Первая проблема заключалась в том, что вы вызывали send метод до правильной инициализации канала, дождитесь, пока он сначала подключится.

Во-вторых, send метод ожидает объект с именем параметра, чтобы сервер мог его как-то идентифицировать:

 App.awpchan.send({message: 'This is a cool chat app.'});
App.awpchan = App.cable.subscriptions.create("AwpchanChannel", {
  connected: function() {
    App.awpchan.send({message: 'This is a cool chat app.'});
  },
  disconnected: function() {},
  received: function(data) {
    return alert(data);
  }
});
// http://js2.coffee/
  

добавлена разработка barlop

И на стороне сервера вы можете сделать

 def received
  puts data["message"]
end
  

Комментарии:

1. Отличный пост, я думаю, что это «receive», а не «received». По крайней мере, в моем тестировании и в документах 5.1 ActionCable. guides.rubyonrails.org/v5.1/action_cable_overview.html Раздел 5.5