1

我正在使用社交留言板(互联网论坛)RoR 开展一个项目,其中每个用户都可以创建多个板并加入来自其他用户的多个板。

我不想重新发明轮子,所以我使用 Devise 进行身份验证,使用 CanCan 进行授权。但是,由于以下原因,我在实施 CanCan 时遇到了一些问题:

class Board < ActiveRecord::Base
  has_many :memberships
  has_many :users , :through => :memberships
end

class User < ActiveRecord::Base
  has_many :memberships
  has_many :boards, :through => :memberships
end

class Membership < ActiveRecord::Base
  ROLE = ['Administrator', 'Moderator','Member', 'Banned']
  belongs_to :user
  belongs_to :board
end

角色不属于用户本人,属于用户与董事会的关系,即Membership。所以知道谁是 current_user 是不够的,我还需要知道正在显示哪个板,所以我认为我必须将 Membership 而不是用户发送到 Ability 类初始化程序?任何指导将不胜感激。

4

1 回答 1

2

你在正确的道路上。

如果您还没有,请将其创建为全新的能力。例如BoardAbility。我发现不要羞于传入额外的依赖项,并让 CanCan 进行尽可能多的合理评估是很有用的。

class BoardAbility
  include CanCan::Ability

  attr_reader :requested_by, :requested_resource

  def initialize requested_by, requested_resource
    return nil unless (requested_by.is_a?(User) && requested_resource.is_a?(Board))

    @requested_by       = requested_by
    @requested_resource = requested_resource

    default_rules
  end

  private

  def default_rules
    # common abilities to all users
    can :flag_offensive,    :all
    can :view_thread_count, :all

    # find this user's role to this board to define more abilities
    role = Membership.where(user_id: requested_by.id, board_id: requested_resource.id).pluck(:role).first

    if ['Administrator', 'Moderator'].include? role
      can :ban_users, Board, {id: requested_resource.id}
    end
  end
end

然后在您的 BoardController 中定义一个私有方法来表示我们没有使用默认的 CanCan Ability 类。

def current_ability
  @current_ability ||= BoardAbility.new(current_user, @board)
end

然后,当您在 BoardController 中时,使用通常的 CanCan DSL。

authorize! :ban_user, @board
于 2013-05-31T05:27:20.997 回答