Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you create multiple channels with Actioncable; how does one pass an in-document variable to the javascript and ruby channels and jobs?

For example, in https://www.youtube.com/watch?v=n0WUjGkDFS0 at 10:36 he mentions the ability to create multiple channels, but how would one actually accomplish this?

According to Rails 5 ActionCable establish stream from URL parameters a variable can be defined and passed as a parameter like:

  def subscribed
    stream_from "room_channel_#{params[:roomId]}"
  end

But in the javascript file prior to passing the data here, how does one pass in the data from the page? The following example renders an error as presumably the cable is defined before the document is loaded.

App.room = App.cable.subscriptions.create { channel: "RoomChannel", roomId: document.getElementById("message_text").getAttribute("data-room")}

Then, if one does successful get the data from the document into the variable here and passes it to the stream_from method, then lastly, how does the right channel get passed into the perform method to be used in the broadcast job?

  def perform(message)
    ActionCable.server.broadcast 'room_channel_???', message: render_message(message) #, roomId: roomId
  end

Thanks!

like image 358
Laser Avatar asked Oct 31 '22 05:10

Laser


1 Answers

I learned a lot by looking to the ActionCable example. I too was confused by the docs that suggest parsing parameters and start streaming immediately on subscription. While this is an option, you might prefer the approach below.

Create a special method that can be called from the client (JS) side, something like start_listening:

class RoomChannel < ApplicationCable::Channel
  # Called when the consumer has successfully
  # become a subscriber of this channel.
  def subscribed
  end

  def start_listening room_data
    stop_all_streams # optional, you might also keep listening...
    stream_for Room.find(room_data['room_id'])
  end

  def stop_listening
    stop_all_streams
  end
end

With this code (and restart of the server) you can now call the following line when you actually have loaded the room:

App.roomChannel.perform("start_listening", {room_id: 20});

Now you can stream data for the room anywhere using broadcast_to. E.g. from a RoomMessage after_safe-action:

RoomChannel.broadcast_to(room, room_message)

This will broadcast the message to all who're listening.

By separating the moment you start to listen to a stream from actually opening the connection makes it easier to set up multiple data streams (There is one connection that can have many channels that can have many streams) (just don't close the old streams when starting a new one ;) ). Connection setup time is also be a bit quicker, although it typically comes at a price of having an opened connection maybe already as soon as a user signs in, something you could easily work around by subscribing just before you start listening.

like image 175
murb Avatar answered Nov 14 '22 05:11

murb