具有两个输入参数的 Pundit 策略
Posted
技术标签:
【中文标题】具有两个输入参数的 Pundit 策略【英文标题】:Pundit policies with two input parameters 【发布时间】:2015-01-29 14:05:42 【问题描述】:我是 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 授权方法只允许两个参数。 有没有办法解决这个问题?
谢谢!
【问题讨论】:
【参考方案1】:我在here找到了答案。
这是我的方式:
在ApplicationController
中添加pundit_user
函数:
class ApplicationController < ActionController::Base
include Pundit
def pundit_user
CurrentContext.new(current_user, foo)
end
创建CurrentContext
类:
/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
【讨论】:
是的 this is 正确的记录方式。 写这么多代码只是为了在没有其他方法需要的情况下将参数传递给单个策略方法有什么意义。 我同意,不幸的是,一些纯粹主义者认为这是一种“代码味道”,但它只会让像我这样的凡人感到困惑。【参考方案2】:依赖于当前用户和域模型是一种代码味道,但如果确实需要,那么您可以使用带有任意数量参数的自定义查询方法,如果需求不满足则引发异常遇见:
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 &&
部分,我只是想展示一个可以在这种情况下使用的单行代码,以消除未经授权的异常,同时仍然需要授权该操作。
【讨论】:
【参考方案3】:我不明白这个想法是什么,将额外的参数传递给 Pundit 是不好的编码。我的意思是,当然,这就像一个大案例陈述。如果您可以通过更好的设计来避免这种情况,那么就这样做,但您通常会面临将授权逻辑散布到其他文件中或将额外信息传递给 Pundit 的选择。
这是我编写的代码,让我可以使用我的 Pundit 类来检查是否允许用户对给定的列进行排序(resource_class 是我编写的另一种方法,它返回关联控制器中关联的 activerecord 类):
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
如果您不希望您的授权逻辑分布在更多类上并希望允许用户对其他用户看不到的字段进行排序,这确实是不可避免的。如果没有创建特殊的活动记录排序对象,这是不可避免的,因为它不是您要返回的任何单个对象的属性,而是它们排序所在的列。
【讨论】:
以上是关于具有两个输入参数的 Pundit 策略的主要内容,如果未能解决你的问题,请参考以下文章
Ruby - Rails 4 - Pundit - 路由#index_fr 的策略和授权错误?
Rails 4 with Pundit & Statesman gem - 对象处于状态时的策略
具有两个输入参数的 std::vector 构造函数[重复]