简体   繁体   English

如何以当前用户或非用户身份更新资源?

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

In my application I have the following resources Post and User. 在我的应用程序中,我有以下资源Post和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.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. 用户必须有两种类型a。 loggedin b. 登录的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.. 另外你可能想尝试瑞安贝茨的cancan gem,或者因为它已经停滞了一段时间你可以使用cancacnan ..

You want to allow updating if one of these conditions are true: 如果满足以下条件之一,您希望允许更新:

  • Post is a guest post 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: 我的方法是使用内存上的'update_user'附加属性进行自定义验证,如下所示:

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). 当然,这个优点是检查逻辑是在模型级别(而不是控制器)的Rails验证下完成的。

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: 我认为user2784630在以下片段中的检查逻辑应该没问题:

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. 但是,如果你担心这个逻辑的全面性,让我们写test或rspec。 Following is an example of test/models/post_test.rb with fixtures: 以下是带有灯具的test / models / post_test.rb示例:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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