Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Broadcast to a User's Turbo Stream using Hotwire Rails

I want to stream model updates using Hotwire in Rails. In the documentation they mention creating a stream using a model but I want to create a dynamic stream per user so that changes to models done by a user are only streamed to that user.

I have a VideoCall model which has and belongs to many users via a joining table so the model looks like this and I have a broadcast as such

class VideoCall < ApplicationRecord
  has_and_belongs_to_many :users

  broadcasts_to ->(video_call) {
    video_call.users.map{|u| "video_calls:user_#{u.id}"}
  }, inserts_by: :prepend

  # more code here
end

On the ERB template where I want to get the updates to the model I have added

<%= turbo_stream_from "video_calls:user_#{current_user.id}" %>

This works if I have one user in a users_video_calls table. But as soon as there are multiple users in a video_call it does not work and I want to broadcast to the stream of all of those users.

Is the approach I am taking correct and how can I achieve broadcasting to multiple users streams dynamically.

like image 665
Encore PTL Avatar asked Jan 15 '21 12:01

Encore PTL


1 Answers

So I solved this the following way. Looking at the source code I realized that it makes sense to override the three callbacks that get called on create, update and destroy. So I removed this code

  broadcasts_to ->(video_call) {
    video_call.users.map{|u| "video_calls:user_#{u.id}"}
  }, inserts_by: :prepend

and replaced it with this

  after_create_commit  -> {
    self.users.each do |u|
      broadcast_action_later_to "video_calls:users_#{u.id}", action: :prepend, target: broadcast_target_default
    end
  }

  after_update_commit  -> {
    self.users.each do |u|
      broadcast_replace_later_to "video_calls:users_#{u.id}"
    end
  }

  after_destroy_commit -> {
    self.users.each do |u|
      broadcast_remove_to "video_calls:users_#{u.id}", action: :prepend, target: broadcast_target_default
    end
  }

In the code above now I can loop through each associated model which in my case is many users per video call and broadcast to the channel name that contains user id. So all the users subscribed to the video call will only get the update and not everyone.

like image 112
Encore PTL Avatar answered Oct 19 '22 09:10

Encore PTL