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

Pundit policies with two input parameters

我是 Rails 的新手,我对以下策略有疑问(使用 Pundit):我想比较两个对象:@record@foo,如您所见:

class BarPolicy < ApplicationPolicy
  def show?
    @record.foo_id == @foo
  end
end

我找不到将第二个参数传递给权威方法 (@foo) 的好方法。

我想做这样的事情:

class BarsController < ApplicationController
  def test
    authorize bar, @foo, :show? # Throws ArgumentError
    ...
  end
end

但是 Pundit 授权方法只允许两个参数。 有办法解决这个问题吗?

谢谢!

我在 here 找到了答案。

这是我的方法:

ApplicationController中添加一个pundit_user函数:

class ApplicationController < ActionController::Base
include Pundit
def pundit_user
    CurrentContext.new(current_user, foo)
end

创建 CurrentContext class:

/lib/pundit/current_context.rb
class CurrentContext
  attr_reader :user, :foo

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

更新初始化 Pundit 方法。

class ApplicationPolicy
  attr_reader :user, :record, :foo

  def initialize(context, record)
    @user = context.user
    @foo = context.foo
    @record = record
  end
end

依赖于当前用户和领域模型是一种代码味道,但如果确实需要,那么您可以使用具有任意数量参数的自定义查询方法,并在要求不符合时引发异常遇见:

class BarPolicy < ApplicationPolicy
  def authorize_test?(foo)
    raise Pundit::NotAuthorizedError, "not authorized to test" unless record.foo_id == foo
  end
end

class BarsController < ApplicationController
  def test
    skip_authorization && BarPolicy.new(current_user, @record).authorize_test?(@foo)
    ...
  end
end

如果不使用 after_action :verify_authorized,则不需要 skip_authorization && 部分,我只是想展示一个可以在这种情况下使用的单行代码,以摆脱未授权的异常同时仍然需要授权该操作。

我不明白这个想法是什么,将额外的参数传递给 Pundit 是糟糕的编码。我的意思是,当然,这就像一个大案例陈述。如果您可以通过更好的设计避免它,那么就这样做,但您通常会面临选择,要么将授权逻辑散布到其他文件中,要么将额外信息传递给 Pundit。

这是我编写的代码,让我可以使用我的 Pundit class 检查是否允许用户对给定列进行排序(resource_class 是我编写的另一种方法 returns 关联控制器中的关联activerecord class:

    def authorize_sort(column, record = resource_class)
        Pundit.policy!(user, record)
        unless policy.allow_sort?(column)
            raise NotAuthorizedError, "Not authorized to sort on column #{column} on record #{record}"
        end
    end

如果您不希望您的授权逻辑分布在更多 classes 上并且希望允许用户对其他用户看不到的字段进行排序,这确实是不可避免的。如果不创建特殊的活动记录排序对象,这是不可避免的,因为它不是您要返回的任何单个对象的 属性,而是它们排序所在的列。