基于CanCan的一种角色在联接表上授权Rails 4用户

4
我正在使用Rails 4.0.0,ruby 2.0.0p247和CanCan 1.6.10。
基于联接表(has_many:through),如何使用CanCan根据用户的角色授权?
我有三个模型:User、Group和GroupUser。
用户和组通过GroupUser表关联为has_many。每个GroupUser还有一个role字段,可以是“editor”或“owner”。一个组可以有多个用户,每个用户具有不同的角色。此外,一个用户可以在多个组中担任角色。
我已经设置了CanCan能力,但它不仅限制对具有正确角色的用户的访问,而且授权所有人。
模型设置如下。还要注意Group有一个返回其所有者列表的方法。
class User < ActiveRecord::Base
  has_many :group_users
  has_many :groups, through: :group_users
end

class Group < ActiveRecord::Base
  has_many :group_users
  has_many :users, through: :group_users

  def owners
    User.find(self.group_users.where(role: 'owner').map(&:user_id))
  end
end

class GroupUser < ActiveRecord::Base
  belongs_to :user
  belongs_to :group
end
CanCan权限管理。请注意,它使用了Group上的owners方法。
class Ability
  include CanCan::Ability

  def initialize(user)

    can :update, Group do |group|
      group.owners.include?(user)
    end

  end
end

视图如下。在这里,不应该看到该链接的用户仍然可以看到它。

<ul class="groups">
    <% @groups.each do |group| %>
        <li>
            <p><%= group.name %></p>
            <% if can? :update, Group %>
                <%= link_to "Edit", edit_group_path(group) %>
            <% end %>
        </li>
    <% end %>
</ul>

最后,视图的控制器操作如下:

def index
  @groups = current_user.groups
end

. . . 一个有趣的事情是,即使在实际使用中它不起作用,以下单元测试也将通过:

test 'user can only update groups they own' do
  ability_one = Ability.new(users(:one)) # Owner
  ability_two = Ability.new(users(:two)) # Not-owner

  assert ability_one.can?(:update, groups(:one))
  assert ability_two.cannot?(:update, groups(:two))
end
1个回答

3

我认为你应该让cancan与实际对象一起工作,在can?方法中传递实际的group对象,而不是Group类:

在视图中:

<% if can? :update, group %>

替代方案:

<% if can? :update, Group %>

通过这种方式,您可以询问是否允许current_user更新实际的group。由于没有为通用的Group对象设置操作能力,因此第二个条件将始终为真。


1
哇,这真的很容易。我在cancan文档中查看了checking abilities wiki,花费了很多时间,但是仍然错过了这个:“重要提示:如果存在块或条件哈希,则在检查类时将忽略它们,并返回true”。感谢您的答案。 - ahuth

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