nolancaster / angular2-actioncable

Integrate ActionCable with Angular2+
25 stars 16 forks source link

How can use ActionCable broadcast_to with specific group of users ? #10

Closed seifoueddine closed 4 years ago

seifoueddine commented 4 years ago

I have a basic setup with rails API + devise_token_auth + actionable and angular9 app for the Front.

I basically want to send notifications to a specific group of users not all users.

My code looks like follows:

connections.rb

module ApplicationCable
 class Connection < ActionCable::Connection::Base
  identified_by :current_user

def connect
  self.current_user = find_verified_user
end

private
def find_verified_user
  uid = request.query_parameters[:uid]
  token = request.query_parameters[:token]
  client_id = request.query_parameters[:client]

  user = User.find_by_uid(uid)

  if user && user.valid_token?(token, client_id)
    user
  else
    reject_unauthorized_connection
  end
end
end
end

appointments.rb

class Appointment < ApplicationRecord
validates_uniqueness_of :start_time
belongs_to :slug
belongs_to :user
belongs_to :property
belongs_to :contact

after_create do
  ChangeAppointmentsJob.perform_later self
end

after_update do
  ChangeAppointmentsJob.perform_later self
end
end

ChangeAppointmentsJob

class ChangeAppointmentsJob < ApplicationJob
  queue_as :default

  def perform(appointment)

    ActionCable.server.broadcast 'appointment_channel', data: appointment
  end

end

AppointmentChannel

class AppointmentChannel < ApplicationCable::Channel
  def subscribed
    stream_from 'appointment_channel'
  end

  def unsubscribed
    stop_all_streams
  end
end

websocket.service.ts

openAppointmentChannel() {
const channel: Channel = this.cableService
  .cable(this.webSocketUrl, { client: this.client, uid: this.uid, token: this.access_token })
  .channel('ws://localhost:3000/cable');
  console.log('open appointments channel');
if (channel) {
  this.appointmentsSubscription = channel.received().subscribe(appointment => {
    this.notifications.create('Info', 'WebSocket notif', NotificationType.Info, { theClass: 'primary', timeOut: 6000, showProgressBar: false });

    this.ourNotificationService.notficateReloadAppointments();
  }, err => {
    console.log(err);
  });
}

}

All works perfectly, but my code broadcasts all users !!

Is there any way to do it with angular? send specific params for example

Or I want to do something like this in rails code

ActionCable.server.broadcast_to( User.where(slug_id: current_user.slug_id) ) 

to send a notification to my Front app but not to all users, just users who had slug_id like the user who created or updated the appointment

any ideas, please!

seifoueddine commented 4 years ago

I found the solution

I send slug_id with the uid, access_token and client for subscribing to the channel and I use it in connection.rb like this

module ApplicationCable
  class Connection < ActionCable::Connection::Base
  identified_by :current_user

def connect
  self.current_user = find_verified_user
end

private
def find_verified_user
  uid = request.query_parameters[:uid]
  token = request.query_parameters[:token]
  client_id = request.query_parameters[:client]
  slug_id = request.query_parameters[:slug_id]
  user = User.where(slug_id: slug_id).find_by_uid(uid)  <-------- get all users with the same slug_id :)

  if user && user.valid_token?(token, client_id)
    user
  else
    reject_unauthorized_connection
  end
end
end
end