我正在使用社交留言板(互联网论坛)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
该角色不属于用户自己,它属于用户与董事会之间的关系,即会员资格。因此,知道谁是current_user还不够,我还需要知道哪个板正在显示,所以我想我必须将Membership而不是用户发送到Ability类初始化器?任何指导将不胜感激。
答案 0 :(得分: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