AnthonyGalli.com
AnthonyGalli.com

Reputation: 2866

How to not send Notification if current_user?

If I make a comment on my own thing I shouldn't get a notification about it. How can we remove this "feature"?

class Comment < ActiveRecord::Base
  after_save :create_notification
  has_many :notifications
  has_many :comment_likes   
  has_many :likers, through: :comment_likes, class_name: 'User', source: :liker
  belongs_to :habit
  belongs_to :stat
  belongs_to :valuation
  belongs_to :goal
  belongs_to :user
  validates :user, presence: true
  default_scope { order('created_at') }

private

  def create_notification
    author = 
      if goal
        goal.user
      #elsif comment_like
      # comment_like.user
      elsif habit
       habit.user
      elsif stat
        stat.user
      elsif valuation
        valuation.user
      end
    notifications.create(
      comment:      self,
      likes:        likes,
      habit:        habit,
      stat:         stat,
      goal:         goal,
      valuation:    valuation,
      user:         author,      
      read:         false
    )
  end
end

Comments can be made on goals, valuations, stats, & habits.

class NotificationsController < ApplicationController
  before_action :correct_user, only: [:destroy]

  def index
    @notifications = current_user.notifications
    @notifications.each do |notification|
      notification.update_attribute(:read, true) 
    end
  end


    def destroy
      @notification = Notification.find(params[:id])
      @notification.destroy
      redirect_to :back
    end

private

  def correct_user
    @notification = current_user.notifications.find_by(id: params[:id])
    redirect_to root_url, notice: "Not authorized to edit this notification" if @notification.nil?
  end
end

CommentsController

class CommentsController < ApplicationController
  before_action :set_commentable, only: [:index, :new, :create]
  before_action :set_comment, only: [:edit, :update, :destroy]
  before_action :correct_user, only: [:edit, :update, :destroy]

  def index
    @comments = @commentable.comments
  end

  def new
    @comment = @commentable.comments.new
  end

  def create
    @comment = @commentable.comments.new(comment_params)
    if @comment.persisted?
      redirect_to @commentable, notice: "Comment created."
    else
      render :new
    end
  end

  def edit
  end

  def update
    if @comment.update_attributes(comment_params)
      redirect_to :back, notice: "Comment was updated."
    else
      render :edit
    end
  end

  def destroy
    @comment.destroy
    redirect_to @comment.commentable, notice: "Comment destroyed."
  end

  def like
    @comment = Comment.find(params[:id])
    @comment_like = current_user.comment_likes.build(comment: @comment)
    if @comment_like.save
      @comment.increment!(:likes)
      flash[:success] = 'Thanks for liking!'
    else
      flash[:error] = 'Too many likes'
    end  
    redirect_to(:back)
  end

  private

  def set_commentable
    @commentable = find_commentable
  end

  def set_comment
    @comment = current_user.comments.find(params[:id])
  end

  def correct_user
    @comment = current_user.comments.find_by(id: params[:id])
    redirect_to root_url, notice: "Not authorized to edit this comment" if @comment.nil?
  end

  def find_commentable
    if params[:goal_id]
      Goal.find(params[:goal_id])
    elsif params[:habit_id]
      Habit.find(params[:habit_id])
    elsif params[:valuation_id]
      Valuation.find(params[:valuation_id])
    elsif params[:stat_id]
      Stat.find(params[:stat_id])
    end
  end

  def comment_params
    params[:comment][:user_id] = current_user.id
    params.require(:comment).permit(:content, :commentable, :user_id, :like)
  end
end

Please let me know if you need further code or explanation. Live long & prosper :]

Upvotes: 1

Views: 164

Answers (1)

Simone Carletti
Simone Carletti

Reputation: 176462

Ideally, you should not rely on callbacks. Especially if, like in this case, your callback must access data which is not available outside the context of the model.

The solution is simple. Rather than creating the comment calling ActiveRecord methods directly in your controller, define a custom method in the Comment itself.

class Comment
  # ...

  def self.create_comment(user, attributes)
    transaction do
        comment = new(attributes)
        if comment.save
            create_notification(user)
            # other after creation methods here
        end
        comment
    end
  end
end

Now the create_notification has access to the current user. Then, in your controller:

def create
  comment = Comment.create(current_user, params[:comments])
  if comment.persisted?
    # saved
  else
    # not saved
    # comment.errors
  end
end

There are several variations. You can also work always with an instance.

class Comment
  # ...

  def create_comment(user, attributes)
    transaction do
        comment.attributes = attributes
        if result = comment.save
            create_notification(user)
            # other after creation methods here
        end
        result
    end
  end
end

def create
  comment = Comment.new
  if comment.create_comment(current_user, params[:comments])
    # saved
  else
    # not saved
    # comment.errors
  end
end

Whatever is your implementation, the point is that callbacks should not be abused. In particular, they should be used to guarantee consistency within the same model, and you should not start introducing explicit dependencies between models or your code will quickly become slow and unmaintainable.

Upvotes: 2

Related Questions