我正在尝试将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
当我这样时,会出现项目索引页面,但不会列出任何项目。
我在这里有两个问题:
如果我将initialize方法更改为:
def initialize(user)
user ||= User.new # guest user
puts "******** Evaluating cancan permissions for: " + user.inspect
can :read, Project
end
......我看到了所有项目,我期待
如果我删除了can:read,项目行,我得到一个安全异常试图点击项目索引页面....也是我期望的。
答案 0 :(得分:0)
只有在项目实例可用时才会评估传递给:read能力的块(@project
)。因为您正在讨论索引操作,所以只有集合可用(@projects
)。这就解释了为什么你的第二个看跌声明永远不会出现。为了限制索引操作,您需要将条件的哈希值传递给can
方法,或者使用范围(除了块)。所有这些信息都在Github上的CanCan wiki中清楚地列出。
因此puts
问题可以解释。没有意义的是没有项目如何展示。在评估索引操作时,CanCan实际上会默认完全忽略该块。这意味着您的能力无论如何都是can :read, Project
(即使在第一个示例中),也可用于索引操作。
我有兴趣让你尝试添加一个简单的范围,只是为了看看它是否有效。尝试:
can :read, Project, Project.scoped do |project|
true
end
然后看看索引操作会发生什么。
编辑:
鉴于您现在可以在索引中看到项目,您似乎需要将范围传递给能力和块。请阅读this Github issue,其中Ryan解释了为什么不对索引操作评估块。
块仅用于基于a定义能力 对象的属性。 [...]这是块应该的唯一情况 因为块仅在对象出现时执行 可用。所有其他条件应在块外定义。
请记住,如果您的能力对于条件哈希来说不是太复杂,那么您应该使用它。条件的哈希在this CanCan wiki page on Github.上解释如果确实需要范围,则需要传入范围和块。让我们说你有上面显示的能力。
@project
)不可用。它将返回在给定范围内的项目,在本例中为Project.scoped
(这将只是所有项目)。 @project
可用,因此如果块的计算结果为true,CanCan将评估该块并允许该动作。因此,您需要传递两者的原因是CanCan可以处理索引和显示操作。在大多数情况下,您的块将定义与作用域相同的内容,只有块将用Ruby编写,而您的作用域将编写Rails的ActiveRecord语法。您可以在此处了解更多相关信息:Defining Abilities with Blocks。