Reputation: 806
Non-users in my application cannot delete or update comments by a user and users only can update or delete there own comments or a non-users comments. The problem I'm having is writing this correctly and safely.
This is how I create a new comment and this works without access to the user_id but I'm not sure what to do with the update and delete methods. Right now they just allow the current user to delete or update comments
CommentsController
def new
@post = Post.find(params[:post_id])
@comment = Comment.new
end
def edit
@post = Post.find(params[:post_id])
@comment = Comment.find(params[:id])
end
def create
@post = Post.find(params[:post_id])
if signed_in?
@comment = current_user.comments.build(comment_params)
else
@comment = Comment.create(comment_params)
end
if @comment.save.....
end
def update
@post = Post.find(params[:post_id])
@comment = current_user.comments.find(params[:id])
if @comment.update(comment_params)..........
end
def destroy
@comment = current_user.comments.find(params[:id])
@comment.destroy
end
private
def comment_params
params.require(:comment).permit(:body, :post_id)
end
I think have to some how get to the @comment.user field but how would I do that if I have to find the comment first? Or, how would this be done if that isn't the right way?
Answer
This is what I ended up doing:
def update
@post = Post.find(params[:post_id])
@comment = Comment.find(params[:id])
if @comment.user == current_user
if @comment.update(comment_params)
redirect_to @comment
else
render action: 'edit'
end
elsif @comment.user.blank?
if @comment.update(comment_params)
redirect_to @comment
else
render action: 'edit'
end
else
redirect_to @comment, notice: "An Error occured"
end
end
Upvotes: 0
Views: 174
Reputation: 3513
I think your best bet is to use an authorization system such as declarative_authorization
, pundit
, or cancancan
. They also provide view helpers that will let you hide the update link from users that can't update a particular comment.
Although if this is the only place you want authorization then writing your own solution as you suggest is probably a better option. You could do something like this:
def CommentsController < ApplicationController
...
def update
@comment.update comment_params
if @comment.authorized_update!(current_user)
redirect_to @comment, status: :accepted
else
redirect_to @comment, status: :unauthorized
end
end
end
Then in your model:
def Comment < ActiveRecord::Base
...
def authorized_update!(current_user)
if user == current_user
self.save
else
errors[:base] << "Unauthorized"
false
end
end
end
You'll probably have to tweak it to fit your needs, but you get the idea.
Upvotes: 1
Reputation: 12818
Assuming that comments created by guest users have user_id
field set to nil, you can do something like
class Post < ActiveRecord::Base
...
scope :comments_editable_by, ->(user_id) { where('user_id is null or user_id = ?', user_id) }
...
end
And use this scope instead of comments
in the update
and destroy
actions.
Upvotes: 1