Mislavoo7
Mislavoo7

Reputation: 697

How to send data between ruby on rails and reactJS via websockets

I'm trying to make an app that uses ruby on rails for the backedn and reactjs for the frontent. I expect tahat several people will use this app at the same time and the app should work without refreshing the page or redirecting to some new routes (except for signin, signout, signup...). For the communication between backend and frontend I'm trying to use websockets but I get errors in the terminal and in the console of the browser. Both error repeat each second or so.

Error I get in the terminal is:

13:58:00 rails.1   | [ActionCable] [[email protected]] Finished "/cable/" [WebSocket] for 127.0.0.1 at 2017-05-04 13:58:00 +0200
13:58:00 rails.1   | [ActionCable] [[email protected]] There was an exception - NoMethodError(undefined method `fetch' for nil:NilClass)
13:58:00 rails.1   | [ActionCable] [[email protected]] /home/mislav/.rvm/gems/ruby-2.3.0/gems/actioncable-5.0.2/lib/action_cable/server/configuration.rb:25:in `pubsub_adapter'
13:58:00 rails.1   | /home/mislav/.rvm/gems/ruby-2.3.0/gems/actioncable-5.0.2/lib/action_cable/server/base.rb:76:in `block in pubsub'
  ...
# here are now a lot of errors like :
13:58:00 rails.1   | /home/mislav/.rvm/gems/ruby-2.3.0/gems/actioncable-5.0.2/lib/action_cable/channel/streams.rb:106:in `block in stop_all_streams'
13:58:00 rails.1   | /home/mislav/.rvm/gems/ruby-2.3.0/gems/actioncable-5.0.2/lib/action_cable/channel/streams.rb:105:in `each'
13:58:00 rails.1   | /home/mislav/.rvm/gems/ruby-2.3.0/gems/actioncable-5.0.2/lib/action_cable/channel/streams.rb:105:in `stop_all_streams'
  ...
14:01:09 rails.1   | /home/mislav/.rvm/gems/ruby-2.3.0/gems/concurrent-ruby-1.0.5/lib/concurrent/executor/ruby_thread_pool_executor.rb:319:in `block in create_worker'
14:01:10 rails.1   | Started GET "/cable" for 127.0.0.1 at 2017-05-04 14:01:10 +0200
14:01:10 rails.1   | Started GET "/cable/" [WebSocket] for 127.0.0.1 at 2017-05-04 14:01:10 +0200
14:01:10 rails.1   | Successfully upgraded to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: Upgrade, HTTP_UPGRADE: websocket)
14:01:10 rails.1   |   User Load (0.5ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = 2 LIMIT $1  [["LIMIT", 1]]
14:01:10 rails.1   | [ActionCable] [[email protected]] Registered connection (Z2lkOi8vYXV0b2Nvb3JkMy9Vc2VyLzI)
14:01:10 rails.1   | +++++++++++++ subscribed method

The last line is just the puts from the subscribed method in the channels. It is there so I can follow how the data flow

Error I get in the chrome console is:

Uncaught TypeError: Cannot read property 'received' of undefined
    at t.notify (eval at <anonymous> (application.js:1187), <anonymous>:1:1715)
    at t.message (eval at <anonymous> (application.js:1169), <anonymous>:1:1778)

The app/channels/users_channel.rb looks like this:

class UsersChannel < ApplicationCable::Channel  
  def subscribed
    puts "+++++++++++++ subscribed method"
    stream_from 'users_channel'
  end

  def speak(data)
    puts "+++++++++++++++ speak method: #{data}"
    ActionCable.server.broadcast 'users_channel', message: data['message']
  end
end 

And the part of the react component (component name is ) that gets and sends data to backend looks like this:

...
  componentDidMount() {
    console.log("component did mount") //I see this in the console

    this.props.cable.subscriptions.create('UsersChannel', {
      message: "messsage",
      connected: function () {
        setTimeout(() => this.perform('speak',
          {data: "some dataaaa"}),
          1000);
      },

      received: function(data) {
        console.log(data);
      }
    });
  }
...

In my react root file I have:

...
import ActionCable from 'action-cable-react'

var actionCable = ActionCable.ActionCable
var cable = actionCable.createConsumer('ws://localhost:5000/cable');
console.log(cable)
/*
console.log(cable) outpust:

n {url: "ws://localhost:5000/cable", subscriptions: t, connection: t, connectionMonitor: t}
> connection: t
> connectionMonitor: t
> subscriptions: t
> url: "ws://localhost:5000/cable"
*/

  ...

  ReactDOM.render(
    <Application cable={cable} />,
    document.getElementById('application')
  );

This is my first try with websockets and I have no clue what's going on. I googled some blogposts and questions on stackoverflow about this topic but I can't get it work. I would be really grateful if you could help me to puts some data from the rails cabel and console.log some data in the browser.

Thank you!

Upvotes: 2

Views: 1119

Answers (1)

Mitch VanDuyn
Mitch VanDuyn

Reputation: 2878

See my comment above. It's hard to answer your question due to the amount of debug necessary. However, if you can't use http://ruby-hyperloop.io then my suggestion would be to use pusher-faker as your websocket transport. (see the pusher-faker gem) its easy to setup, and I have found it much easier to diagnose system problems. Once you get things working you can switch back to action-cable.

I know it's not a great answer, but it's what I would do :-)

Upvotes: 1

Related Questions