Search code examples
ruby-on-railsactioncable

in rails with action cable, not able to send from client to server


in rails with action cable, I can't get a message from client to server, though I can send from server to channel to client.

You can see all the files here and at the end i've shown them with cat as I show all commands used in the making of the program

Looking in awpchan_channel.rb I have def subscribed, that works, a puts command in there will write to the server. But def receive(data) never runs. I wrote a puts in there and it isn't executing.

But I do have a line in the js file that is meant to send a string from client to server. App.awpchan.send('This is a cool chat app.'); But it isn't doing it.

I did have it in coffeescript but that didn't do it either.

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 (which I renamed the filename and extension of to oldawpchan.oldcoffee, as i'm not using it, am using theawpchan.js instead)

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 (which is blank)

Here is how I created the program

~/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

added

Applying arieljuod's suggestion, within the js file, putting the send line within the body of the connect method. So that it doesn't send too early.

That improves things, now I get this message

just after the server says

AwpchanChannel is transmitting the subscription confirmation
AwpchanChannel is streaming from abcdstrm

it gives this error now (this would be when the send command executes)

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...

Solution

  • The first problem was that you were calling the send method before the channel is properly initialized, wait for it to get connected first.

    The second thing is that the send method expects an object with the name of the parameter so the server can identify it somehow:

    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/
    

    added elaboration by barlop

    And at the server side you can do

    def received
      puts data["message"]
    end