Reputation: 193
I am using polymorphic association for comments. I want to send notification to all user who comments on post.
comment.rb
class Comment < ApplicationRecord
belongs_to :user
belongs_to :commentable, polymorphic: true
has_many :comments, as: :commentable
validates :comment, presence: true
after_create :notifications
def notifications
#Create Notification
users = ????
(users-[@current_user]).each do |user|
Resque.enqueue(NotifyJob, Notification.create(
recipient: user,
actor: @current_user,
action: "posted",
notifiable: @comment))
end
end
end
user.rb
class User < ApplicationRecord
has_many :posts, dependent: :destroy
has_many :comments, as: :commentable, dependent: :destroy
has_many :notifications, foreign_key: :recipient_id, dependent: :destroy
end
post.rb
class Post < ApplicationRecord
belongs_to :user
validates :comment, presence: true
validates :user_id, presence: true
has_many :comments, as: :commentable
end
comments_controller.rb
module Api
module V1
class CommentsController < ApplicationController
skip_before_action :verify_authenticity_token
before_action :authorize_request
before_action :find_commentable
def new
@comment = Comment.new
end
def create
@comment = @commentable.comments.new(comment_params)
@comment.user = @current_user
if @comment.save
render json: @comment, status: :created
else
render json: { errors: @comment.errors.full_messages },
status: :unprocessable_entity
end
end
def show
@comment = Comment.find(params[:id])
if [email protected]?
render json: @comment, status: :ok
else
render json: {errors: @comment.errors.full_messages}, status: :unprocessable_entity
end
end
private
def comment_params
params.permit(:comment)
end
def find_commentable
@commentable = Comment.find_by_id(params[:comment_id]) if params[:comment_id]
@commentable = Post.find_by_id(params[:post_id]) if params[:post_id]
end
end
end
end
Upvotes: 3
Views: 357
Reputation: 193
I didn't make much changes. I just made changes like this on:
comment.rb
class Comment < ApplicationRecord
belongs_to :user
belongs_to :commentable, polymorphic: true
has_many :comments, as: :commentable
validates :comment, presence: true
private
after_commit :create_notifications, on: [:create]
#Create Notification
def create_notifications
commentable = self.commentable
commentors= Comment.where(commentable: commentable).pluck(:user_id)
users = User.find(commentors)-[self.user]
users.each do |user|
Resque.enqueue(NotifyJob, Notification.create(
actor: self.user,
recipient: user,
action: "posted",
notifiable: self.commentable))
end
end
end
Upvotes: 2
Reputation: 4640
Your first problem is in User
model. You have
has_many :comments, as: :commentable, dependent: :destroy
but Comment
model belongs_to :user
and have user_id
, it means that in User
should be
has_many :comments, dependent: :destroy
In this case you can get all user comments easily with User.first.comments
The second one is callback. Vyacheslav Loginov is right about bad practice to put this complex logic inside the controller action, but callbacks are not good practice too. Not sure which of them is worse. You will create notification on every comment creation, even from console. Notifications will be created in every test setup where you create commnets. Not sure if that it is what you really want.
Better option is to create separate ServiceObject to handle notifications
class CommentsController < ApplicationController
def create
@comment = @commentable.comments.new(comment_params)
@comment.user = @current_user
if @comment.save
NotificationSender.new(@comment).comment_notification
render json: @comment, status: :created
else
render json: { errors: @comment.errors.full_messages },
status: :unprocessable_entity
end
end
end
class NotificationSender
def initialize(resource)
@resource = resource
end
# you can add here all other notifications as methods
def comment_notification
users = User.where(id: @resource.commentable.comments.pluck(:user_id)).
where.not(id: @resource.user_id)
users.each do |user|
Resque.enqueue(
NotifyJob,
Notification.create(
recipient: user,
actor: @resource.user,
action: "posted",
notifiable: @resource
)
)
end
end
end
Upvotes: 2