如何处理cancan中由父对象定义的:create权限?

8

假设你正在编写Blogger的软件。

每个用户只能在拥有博客的情况下创建博客文章。在这种情况下,CanCan通常会定义以下能力检查:

user.can? :create, Post

然而,仅当用户是当前博客的所有者时,才能创建帖子,并且没有办法只使用其类名引用当前博客。我真正需要做的是:

user.can? :create, Post, @current_blog

这样,在cancan定义中,我可以说

can :create, Post do |post, blog|
  user == blog.owner
end

这是可能的,还是我对我的方法有些困惑?
2个回答

8

基于当前对象的父级定义一个能力:

can :create, Post, :blog => { :user => user }

这将确保当前用户仅能为自己拥有的博客创建新的帖子记录。
  • 使用Post.blog_id查找父级Blog记录
  • 比较Blog.user_id字段和current_user.id字段
此外,请确保在加载和授权您的帖子资源时使用:through声明,以便CanCan知道父记录是谁。
PostsController:

load_and_authorize_resource :through => :blog

请查看 GitHub 上的 CanCan wiki 以获取更多详情。


1
最后的":through => :blog"是关键。非常感谢! - rfsbsb

0

您可以使用以下代码:

user.can? :create_posts, @current_blog

或者

user.can?:update, @current_blog

代替以下代码:

user.can? :create, Post, @current_blog

当然,您可能需要从load_and_authorize_resource中删除newcreate操作。并且需要自己测试“授权”。

def new
unauthorized! if cannot? :create_posts, @current_blog
end


你知道如何处理实际的能力定义吗?它通常采用can :create Post do |post_instance|...这种形式,因此不清楚仅通过传递不同的变量如何工作? - Peter Nixey
对于您的示例,我会使用can(:create_posts, Blog) do |blog| user == blog.owner end。因此,在PostsController.new中测试是在@current_blog上进行的,而不是在Post上。 - Foton
我不确定那样会起作用,因为我相信CanCan根据传入的对象类型索引权限,所以如果传入blog,它将查看博客权限。最终我解决的方法是设置一个新对象:user.can? :create, @current_blog.posts.new - 这样我就可以传递一个帖子对象并仍然读取其父级。 - Peter Nixey
@current_blog.posts.new 看起来不错,但它会在 @current_blog.posts 中生成新的帖子实例,这可能会成为以后使用时的问题。有什么想法可以避免这个问题吗? - Sebastian vom Meer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接