React with Rails REST api - actioncable

751 Views Asked by At

I have a react frontend(not using the react-rails gem) and i want to use Rails api for realtime interaction. I have this post.coffee code in my rails already working for ActionCable:

App.post = App.cable.subscriptions.create "PostChannel",
connected: ->

disconnected: ->

received: (data) ->
console.log(data)
document.getElementById('test').innerHTML = data['message']

notify: (message) ->
@perform 'notify', message: message

and this post_channel.rb

class PostChannel < ApplicationCable::Channel
  def subscribed
    stream_from "post_channel"
  end

  def unsubscribed
    # Any cleanup needed when channel is unsubscribed
  end

  def notify(data)
    ActionCable.server.broadcast 'post_channel', message: data['message']
  end
end

working example:

working example

now in my react app, lets say on page load [ componentWillMount() ], I want to 'call' the notify method from the post_channel.rb. How will I do it? I have searched some method and saw this post's accepted answer: How to use ActionCable as API

So in my react app's componentWillMount() lifecycle, I have this code:

  componentWillMount() {
     var cable = ActionCable.createConsumer('ws://localhost:8000/cable');
     cable.server.broadcast 'post_channel', { message: 'ji'}
  }

I got the ws url from my development.rb: enter image description here

The code in componentWillMount does not even call the websocket in my rails app. How to do this? I dont see much resource. or could you recommend any websocket library best for react-rails stack?

1

There are 1 best solutions below

0
On

Solution

should be similar to your Rails .coffee code

componentWillMount() {
  var cable = ActionCable.createConsumer('ws://localhost:8000/cable');

  var subscription = cable.subscriptions.create('PostChannel',
    {
      connected: function() {
        // this is where it calls the `notify` method in your `post_channel` immediately once this subscription has successfully connected
        this.notify({ message: 'ji'});

        // it seems to me that this `notify` code above is just a once-off action and that you won't be using this subscription anymore;
        // if that's the case then, uncomment the line below to immediately unsubscribe immediately after performing the `notify` above
        // this.unsubscribe();
      },
      received: function(data) {
        // there is a new message; do something about it here...
        console.log(data.message);
      },
      notify: function(message) {
        this.perform('notify', message: message)
      }
    }
  )
}

Recommendation

  • You'd ought to only have one consumer object (use only ActionCable.createConsumer('ws://localhost:8000/cable'); once), and make it global in your app to speed things up (and less code), because you'll always only have one websocket endpoint anyway (the Rails server), unless of course you have different multiple websocket URLs (on different Rails servers or apps?). You might also then want to make the subscription variable above to be global, so you can do .notify(...) anywhere you want, and not instantiating another subscription each time.

  • I just built a gem live_record that syncs records to the JS-client. Though it does not intentionally support pushing "messages" to the Rails server, but just in case you might find it useful, feel free to try it out! :)