简体   繁体   中英

How to allow users to delete or update non-user resources and only there own?

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

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM