简体   繁体   中英

How to update a resource as current user or a non-user?

In my application I have the following resources Post and User. I want a user to be able to update their own post and guest post and I want guest to be able to update other guest post but not a users. A guest is simply a non-user ( @post.user.blank ).

Post Model
  belongs_to :user
  # columns: user_id, name, body
end

User Model
  has_many :posts
end

My controller is where I get confused because I'm not sure how to make it so updating a Post can be done by a current user or guest without allowing everyone to update anyones post. Mainly another user updating another users post.

  def update
    @post = Post.find(params[:id])
    if @post.update(post_params)
      redirect_to @post
    else
      render action: 'edit'
    end
  end

  def post_params
    params.require(:post).permit(:name, :body)
  end

I was thinking of doing:

  def update
    @post = Post.find(params[:id])
    if @post.user == current_user or @post.user.blank?
      if @post.update(post_params)
        redirect_to @post
      else
        render action: 'edit'
      end
    end
  end

But I'm not sure how safe this is. Seems like a user can get to another users post.

Is this right? How could I do this?

I'll do it like this since it would be better for logic to be in model(or maybe in service object):

User has to have two types a. loggedin b. guest

class Post < AR::Base
  ...
  ...
  def created_by_guest?
    self.user == nil #probably created by guest if user is nil
  end

  def update_by_user(user, attributes)
    return false if user.guest and self.created_by_guest?
    #add code to try updating return true if it worked and false if did not work
  end
end

in your controller

def update
  @post = Post.find(params[:id])
  if @post.update_by_user(current_user, update_params)
    #redirect to show
  else
    #edit page
  end
end

Also you might want to try cancan gem by Ryan bates or since it has been stagnant for a while you can use cancacnan..

You want to allow updating if one of these conditions are true:

  • Post is a guest post
  • User is the post's owner

Let's create a method in the model to check if a user is allowed to update based on passing one of those two conditions:

Post Model
  belongs_to :user
  # columns: user_id, name, body

  def updatable_by?(user)
    @user_id.nil? || user == self.user # return true for guest post OR post owner
  end
end

Then, update pending the result of the check:

def update
  @post = Post.find(params[:id])
  if @post.updatable_by?(current_user) # <-- update if current_user is allowed
    if @post.update(post_params)
      redirect_to @post
    else
      render action: 'edit'
    end
  end
end

My approach is to use custom validation with 'update_user' additional attribute on memory as follows:

class Post < ActiveRecord::Base
  belongs_to :user

  attr_accessor :update_user
  validate :validate_user_scope, on: :update

  private

  def validate_user_scope
    if !(user.blank? || user == update_user)
      errors.add(:update_user, :not_permitted)
    end
  end
end


class User < ActiveRecord::Base
  has_many :posts
end

This merit is, of course, check logic is done under Rails validation at model level (not controller).

User's access scope (or access permission) should be one of "business logic" and "business logic" should be one of Model logic so that it would be good to write in model level, I think.

I think user2784630's check logic at the following fragment should be OK:

if @post.user == current_user or @post.user.blank?

but, if you worry about the comprehensiveness of this logic, let's write test or rspec. Following is an example of test/models/post_test.rb with fixtures:

require 'test_helper'

class PostTest < ActiveSupport::TestCase
  ...
  # test all of posts of guest, user-A, and user-B are updated by
  # guest, user-A, and user-B
  test "update guest post by user_A" do
    p = posts(:guest_post)
    p.update_user = users(:user_A)
    assert p.valid?
  end
  ...
end

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