Ruby on rails 在Pundit中使用没有实例变量的策略帮助程序
所以我决定提供一个尝试用户授权的解决方案。我想知道在实例变量可能为nil的情况下如何使用Ruby on rails 在Pundit中使用没有实例变量的策略帮助程序,ruby-on-rails,ruby,ruby-on-rails-3,authorization,pundit,Ruby On Rails,Ruby,Ruby On Rails 3,Authorization,Pundit,所以我决定提供一个尝试用户授权的解决方案。我想知道在实例变量可能为nil的情况下如何使用策略帮助器,如下所示: app/views/projects/index.html.slim h1 Projects (...) - if policy(@project).create? = link_to 'New Project', new_project_path app/controllers/projects\u controller.rb (...) def index @projec
策略
帮助器,如下所示:
app/views/projects/index.html.slim
h1 Projects
(...)
- if policy(@project).create?
= link_to 'New Project', new_project_path
app/controllers/projects\u controller.rb
(...)
def index
@projects = Project.all
end
(...)
app/policies/project_policy.rb
class ProjectPolicy < Struct.new(:user, :project)
def create?
user.has_role? :admin
end
class ProjectPolicy
我想在Projects#index页面上显示一个“New Project”链接,但我在此视图中没有@Project实例变量,因此出现错误:
专家::项目中未定义错误#索引
找不到的策略NilClassPolicy
出现此错误显然是因为我传递的实例变量是nil,因此有一个NilClass,显然我不需要授权
我找到了两个解决此问题的方法,使其能够正确运行,但没有一个是合适的:
policy(@projects[0])
@project=project.new
(或直接在类似于上面的视图中:策略(project.new)
)有没有关于实现这一目标的正确方法的建议?你提出的第二个解决方案就是我所做的
- if policy(@project).create?
= link_to 'New Project', new_project_path
此处新记录的策略检查应使用Project.new
(无论它是否分配给实例变量)
无论如何,必须将
Project
的实例传递给policy
帮助程序,以便Pundit派生policy类ProjectPolicy
执行create?
检查查找。当您传入nil
时,这就是为什么您会看到Pundit派生NilClassPolicy
通常单个实例与类中的所有其他实例具有相同的策略-这实际上是Pundit的正常工作方式。在这种情况下,您实际上并不关心属于特定实例的策略;相反,您正在寻找一类对象的策略
policy
方法用于标识对象的策略类
def find
if object.respond_to?(:policy_class)
object.policy_class
elsif object.class.respond_to?(:policy_class)
object.class.policy_class
else
klass = if object.respond_to?(:model_name)
object.model_name
elsif object.class.respond_to?(:model_name)
object.class.model_name
elsif object.is_a?(Class)
object
else
object.class
end
"#{klass}Policy"
end
end
您可以将任何对象传递给策略方法。因为类是对象,所以可以传入类。在find
方法中,第一个条件检查您传递的对象是否响应policy\u类
,因此您可以在项目
类中定义一个名为policy\u类
的方法,并让该方法返回您的ProjectPolicy
类
class Project < ActiveRecord::Base
def self.policy_class
ProjectPolicy
end
end
class项目
如果不定义policy_类方法,那么前两个条件将失败,find方法将尝试构造策略类名。它首先查看object.model\u名称。如果您在Rails中,并且您的模型扩展了ActiveModel::Naming(ActiveRecord::Base就是这样做的),那么它将已经响应model\u name
,如果您正在执行典型的Rails ey操作,那么这个名称正是您想要的:它将返回“Project”
。然后,find方法将在其末尾附加“Policy”,以使成为“ProjectPolicy”
。如果是其他对象,则使用该对象的名称,这在大多数情况下也适用
或者,您可以传递任何表示您想要策略的对象类型的原型对象。这意味着您可以使用Policy.new
创建一个,也可以从@policies
数组中获取一个。正如你所说,这些选择都有缺点
你有很多选择。没有特别“正确”的方法。我更喜欢在这种情况下传递这个类,因为它最有语义意义
class Project < ActiveRecord::Base
def self.policy_class
ProjectPolicy
end
end