具有两个输入参数的 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 上并且希望允许用户对其他用户看不到的字段进行排序,这确实是不可避免的。如果不创建特殊的活动记录排序对象,这是不可避免的,因为它不是您要返回的任何单个对象的 属性,而是它们排序所在的列。
我是 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 上并且希望允许用户对其他用户看不到的字段进行排序,这确实是不可避免的。如果不创建特殊的活动记录排序对象,这是不可避免的,因为它不是您要返回的任何单个对象的 属性,而是它们排序所在的列。