Rails 4 - pundit - 如何编写 if 语句来检查用户权限

Posted

技术标签:

【中文标题】Rails 4 - pundit - 如何编写 if 语句来检查用户权限【英文标题】:Rails 4 - pundit - how to write if statement to check user permissions 【发布时间】:2016-08-24 01:29:24 【问题描述】:

我正在尝试学习如何在我的 Rails 4 应用中使用 pundit。

我有一个潜在的使用政策。潜在使用表有一个名为 :user_id 的属性。

我希望允许用户在创建实例时更新它们。我正在尝试弄清楚如何使更新操作起作用。

我目前的尝试如下所示。

class PotentialUsePolicy < ApplicationPolicy

    attr_reader :user, :record

  def initialize(user, record)
    @user = user
    @record = record
  end


    def index?
        true if user.is_admin?
    end

    def show?
        true

    end

    def new?
      true
  end

    def create?
        new?
    end

    def update?
        if @user.id == @potential_use.user_id

        # if user.id == potential_use.user_id
            true
        else
            false
        end
    end

    def destroy?
        update?
    end

    def edit?
                true
    end

    def potential_use
        record
    end 

end

当我尝试这些时,我不断收到错误消息:

undefined method `user_id' for nil:NilClass

我不明白为什么会收到此消息。当我查看控制台时,我可以看到一个具有用户 ID 的条目。

p = PotentialUse.where(project_id: 26)
  PotentialUse Load (0.5ms)  SELECT "potential_uses".* FROM "potential_uses" WHERE "potential_uses"."project_id" = $1  [["project_id", 26]]
 => #<ActiveRecord::Relation [#<PotentialUse id: 9, comment: "adsfsfdadfasdddxxddbbdd", project_id: 26, created_at: "2016-08-18 23:16:06", updated_at: "2016-08-24 01:06:00", user_id: 1, private_comment: false>]> 
2.3.0p0 :016 > 

当我查看视图时(不尝试使用 pundit 策略,页面会呈现所有正确的内容,包括用户名(由 user_id 访问)。

我的潜在使用控制器中的更新操作有:

def update
    authorize @potential_use
    respond_to do |format|
      if @potential_use.update(potential_use_params)
        format.html  redirect_to @project, notice: 'Potential use was successfully updated.' 
        format.json  render :show, status: :ok, location: @potential_use 
      else
        format.html  render @project 
        format.json  render json: @potential_use.errors, status: :unprocessable_entity 
      end
    end
  end

谁能看到我做错了什么?

【问题讨论】:

【参考方案1】:

检查用户是否有权从视图中对策略执行操作:

<% if policy(@post).update? %>
  <%= link_to "Edit post", edit_post_path(@post) %>
<% end %>

【讨论】:

【参考方案2】:

您的错误是因为您调用了@potential_use.user_id,但从未在策略类中声明@potential_use。您将potential_use 定义为一个方法,但在该方法中您调用record,而不是@record

因此,要修复它,您应该调用 potential_use 而不是 @potential_use 并将方法更改为:

def potential_use
    @record
end

或者简单地说,调用@record.user_id 而不是@potential_use.user_id

此外,正如您在Pundit readme 中看到的,当您从ApplicationPolicy 继承时,您不需要声明:

attr_reader :user, :record

def initialize(user, record)
  @user = user
  @record = record
end

因为它已经在父类中了。

【讨论】:

【参考方案3】:

您使用访问者访问授权对象。在您的示例中,您可能调用了

authorize @potential_use

在您的控制器更新操作中。更新?控制器上的方法如下所示:

def update?
    user.id == record.user_id
end

【讨论】:

但是如果在我的策略中有一个称为潜在用途的方法,它被定义为记录。所以——我认为我的尝试(评论版)和你的一样。它不起作用(我尝试使用'@'符号的版本也没有。 另外,我尝试了你的建议,但它给出了这个错误:undefined method `user_id' for #<0x007fba181c5f00>

以上是关于Rails 4 - pundit - 如何编写 if 语句来检查用户权限的主要内容,如果未能解决你的问题,请参考以下文章

Rails 4 with Pundit & Statesman gem - 对象处于状态时的策略

Rails 5,具有命名空间资源的Pundit

Rails 6 - Pundit“策略包装器”

Authorization With Pundit

具有两个输入参数的 Pundit 策略

如何为 Rails 中枚举中列出的角色添加模型?