在Pundit中使用策略助手,没有可用的实例变量

Kul*_*lbi 3 ruby authorization ruby-on-rails ruby-on-rails-3 pundit

所以我决定尝试权威的用户授权解决方案.我想知道如何policy在视图中使用帮助器,实例变量可能是nil,如下面的简单情况:

应用程序/视图/项目/ index.html.slim

h1 Projects
(...)
- if policy(@project).create?
  = link_to 'New Project', new_project_path
Run Code Online (Sandbox Code Playgroud)

应用程序/控制器/ projects_controller.rb

(...)
def index
  @projects = Project.all
end
(...)
Run Code Online (Sandbox Code Playgroud)

应用程序/政策/ project_policy.rb

class ProjectPolicy < Struct.new(:user, :project)
  def create?
    user.has_role? :admin
  end
Run Code Online (Sandbox Code Playgroud)

我想在Projects #index页面上显示一个"New Project"链接,但是我在这个视图中没有@project实例变量,但是收到错误:

Pundit :: Projects#index中的NotDefinedError

无法找到策略NilClassPolicy

错误显然是因为我传递了@projectnil的实例变量,因此有一个NilClass,显然我没有必要授权.

我找到了2个解决这个问题的方法,使它运行正常,但它们似乎都不合适:

  1. 在视图中使用现有的@projects变量,即: policy(@projects[0])
  2. 向项目添加一行#index controller action定义此实例变量,例如.@project = Project.new(或直接在视图类似于上文:policy(Project.new))

第一个解决方案将导致@projects数组中的相同错误为空,而第二个解决方案将创建冗余实例变量.所有策略帮助程序需要知道的是我希望在哪个类上强制执行授权逻辑.

有关正确实现方法的任何建议吗?

dee*_*our 5

你提出的第二个解决方案是我的工作.

- if policy(@project).create?
  = link_to 'New Project', new_project_path
Run Code Online (Sandbox Code Playgroud)

此处对新记录的策略检查应该使用Project.new (是否将其分配给实例变量).

- if policy(Project.new).create?
  = link_to 'New Project', new_project_path
Run Code Online (Sandbox Code Playgroud)

无论如何,Project必须将实例传递给policy帮助程序,以便Pundit派生策略类ProjectPolicy来执行create?检查查找.当你传入nil它时,你就会看到Pundit派生出来了NilClassPolicy.