使用CanCan在Rails 4上授权用户在连接表中使用一个角色

时间:2013-11-20 13:48:21

标签: ruby-on-rails permissions ruby-on-rails-4 authorization cancan

我正在使用Rails 4.0.0,ruby 2.0.0p247和CanCan 1.6.10。

如何根据用户在联接表中的角色授权使用CanCan的用户(has_many:through)?

我有3个模型:UserGroupGroupUser

用户和组通过GroupUser表关联为has_many。每个GroupUser还有一个role字段,可以是“编辑者”或“所有者”。一个组可以有多个用户,每个用户具有不同的角色。此外,用户可以在多个组中拥有角色。

我的应用设置包含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能力。请注意,它在群组中使用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 个答案:

答案 0 :(得分:3)

我认为你应该让cancan在这里使用真实对象,将实际的group对象传递给can?方法而不是Group类:

在视图中:

<% if can? :update, group %>

而不是:

<% if can? :update, Group %>

这样,如果cancan能够current_user实际的:update,您会问group。由于没有为通用Group对象设置操作的能力,因此第二个条件将始终为真。