3

我正在尝试将 cancan 整合到我的第一个 Ruby on Rails 应用程序中。

我在开始时遇到问题......这肯定是一些基本的东西。

我的应用程序有一个项目列表,用户可能有权查看其中的任意数量,也可能没有权限。

我将此添加到我的 ProjectsController 中:

class ProjectsController < ApplicationController
  load_and_authorize_resource

我的初始化方法如下所示:

  def initialize(user)
    user ||= User.new # guest user
    puts "********  Evaluating cancan permissions for: " + user.inspect
    can :read, Project do |project|
      puts "********  Evaluating project permissions for: " + project.inspect
      # project.try(project_users).any?{|project_user| project_user.user == user} 
      1 == 1  #POC test!
    end
  end

当我有这个时,会出现项目索引页面,但没有列出任何项目。

我在这里有2个问题:

  1. 由于所有项目都返回 true,因此不应该出现所有项目吗?
  2. 第二个 puts 语句没有写入 rails 服务器控制台,但第一个是。这是为什么???

如果我将初始化方法更改为:

  def initialize(user)
    user ||= User.new # guest user
    puts "********  Evaluating cancan permissions for: " + user.inspect
    can :read, Project
  end

...我看到了所有的项目,正如我所期望的那样

如果我删除 can :read, Project 行,我会得到一个试图访问项目索引页面的安全异常......也是我所期望的。

4

1 回答 1

0

仅当项目实例可用时才评估传递给 :read 能力的块 ( @project)。因为您正在谈论索引操作,所以只有集合可用(@projects)。这解释了为什么您的第二个 puts 语句从未出现。为了限制您的索引操作,您需要将条件哈希传递到can方法中,或者使用范围(除了块之外)。所有这些信息都在 Github 上的 CanCan wiki 中明确列出。

所以puts问题是可以解释的。没有意义的是没有项目展示。在评估索引操作时,CanCan 实际上会默认完全忽略该块。这意味着can :read, Project无论如何(即使在第一个示例中)您的能力对于索引操作都是必不可少的。

我有兴趣让您尝试添加一个简单的范围,看看它是否会起作用。尝试:

can :read, Project, Project.scoped do |project|
  true
end

然后看看索引操作会发生什么。

编辑:

鉴于您现在可以在索引中看到项目,您似乎需要将范围传递给能力和块。请阅读这个 Github 问题,其中 Ryan 解释了为什么没有在索引操作上评估块。

块仅用于根据对象的属性定义能力。[...]这是唯一应该使用块的情况,因为该块仅在对象可用时才执行。所有其他条件都应在块外定义。

请记住,如果您的能力对于条件哈希来说不是太复杂,那么您应该使用它。条件哈希在 Github 上的 CanCan wiki 页面上进行了解释。如果确实需要范围,则需要传入范围和块。假设您具有上述能力。

  1. On the index action, CanCan will disregard the block because a Project object (@project) is not available. It will instead return projects that are within the scope given, in this case Project.scoped (which will just be all projects).
  2. On the show action, @project is available, so CanCan will evaluate the block and allow the action if the block evaluates to true.

So the reason you need to pass both is so that CanCan can handle both the index and show actions. In most cases, your block will define the same thing as the scope does, only the block will be written in Ruby while your scope will be written Rails' ActiveRecord syntax. You can fine more information about here: Defining Abilities with Blocks.

于 2013-03-29T14:05:16.273 回答