Reputation: 2988
I have an Appointment
model, I want to send a broadcast to the frontend application in react every time an appointment is created or updated. Here's the code of my model.
class Appointment < ApplicationRecord
belongs_to :tutor, class_name: 'User'
belongs_to :student, class_name: 'User'
after_create :appointment_notification
after_update :appointment_notification
def appointment_notification
Notification.create(
from: student,
to: tutor,
name: :student_create_appointment, # here you can detect any type
model: :appointment
)
end
end
and Notification
model and table to save the history of all notifications
class Notification < ApplicationRecord
belongs_to :from, class_name: 'User', foreign_key: :from_id
belongs_to :to, class_name: 'User', foreign_key: :to_id
before_create :set_seen
after_create :push_notification
def set_seen
self.seen = false
end
def push_notification
if to.user_push_notification.respond_to?(name) &&
to.user_push_notification.send(name)
PushNotificationJob.perform_later(
from: from,
to: to,
message: message(:push),
name: name,
created_at: created_at.iso8601
)
end
end
def message(gate_scope)
# gate_scope can be 'sms' or 'push' or 'email.body' if we have nested yml in translations
I18n.t(
"notification.#{model}.#{name}.#{gate_scope}",
from: from,
to: to,
created_at: created_at
)
end
end
I have created a NotificationsChannel
to look like so:
class NotificationsChannel < ApplicationCable::Channel
def subscribed
stream_from "notification_channel:#{current_user.id}"
end
def unsubscribed
stop_all_streams
end
end
And a PushNotificationJob
to look like this:
class PushNotificationJob < ApplicationJob
queue_as :default
def perform(from:, to:, message:, name:, created_at:)
NotificationsChannel.broadcast_to(
to,
type: name,
caller: from,
message: message,
created_at: created_at
)
end
end
Everything works great, the only missing link is the part where I get to broadcast it to the user on the frontend: Here's what I have on the JavaScript side so far.
App.notificationsChannel = App.cable.subscriptions.create(
'NotificationsChannel',
{
connected: function() {
// Called when the subscription is ready for use on the server
console.log('Notification Channel connected.');
},
disconnected: function() {
// Called when the subscription has been terminated by the server
console.log('Notification Channel disconnected.');
},
received: function(data) {
// Called when there's incoming data on the websocket for this channel
console.log(data);
}
}
);
// App.notificationsChannel.send({ test: 'data' });
I can't get anything to print in the browser console, except what's there in connect and disconnect.
After creating an Appointment this is what my terminal log looks like.
Any idea what else I'm missing and what I need to do?
BTW, I also created these routes URLs in the route file
resources :notifications, only: :index do
collection do
post 'seen_all', to: "notifications#seen_all"
end
member do
post :seen
end
end
And finally my NotificationsController
.
module API
module V1
class NotificationsController < ApiController
before_action :set_user
def index
@user.incoming_notifications.page(params[:page]).per(params[:per_page])
end
def seen_all
Notification.where(seen: false, to_id: @user.id).update(seen: true)
end
def seen
@user.incoming_notifications.find_by(id: params[:id]).seen!
end
private
def set_user
@user = current_user
end
end
end
end
Please guide me on how to print the notifications in the browser console and thereafter, consume it in React through the API. Thanks.
Upvotes: 0
Views: 1092
Reputation: 837
Please check the Delayed Job Logs for more information. Give the following a try:
def perform(from:, to:, message:, name:, created_at:)
ActionCable.server.broadcast "notification_channel:#{to.id}", { type: type, caller: caller.name, message: message, created_at: created_at }
end
A tip here: use after_commit: :do_something, on: [:create, :update]
instead of using after_create
. This will ensure that the notification will be triggered only after successful creation of Appointment.
Upvotes: 2
Reputation: 388
you can use the following tutorial to get this working. This is quite simple to achieve Using Action Cable With React I have already followed the guidelines for a few projects.
Upvotes: 0