使用角色设置多对多系统非常简单:
class User
has_many :user_roles
has_many :roles, through: :user_roles
def has_role?(role)
roles.where(name: role).any?
end
end
class Role
has_many :user_roles
has_many :users, through: :user_roles
end
class UserRole
belongs_to :role
belongs_to :user
validates_uniqueness_of :role, :user
end
只需确保在 UserRole 上为角色和用户创建唯一索引:
add_index :user_roles, [:role_id, :user_id], unique: true
实现经理要求的最简单和高效的方法是添加一个
mananger_id 列到 users 并设置一个自引用的一对多关系:
class User
has_many :user_roles
has_many :roles, through: :user_roles
belongs_to :manager, class_name: 'User'
has_many :subordinates, foreign_key: :manager_id, class_name: 'User'
validate :authorize_manager!
def has_role?(role)
roles.where(name: role).any?
end
private
def authorize_manager!
if manager.present?
errors.add(:manager, "does not have manager role") unless manager.has_role?("manager")
end
end
end
另一种方法是使用资源范围角色。
最好的部分是您没有自己构建它。社区创建了一个名为Rolify 的优秀gem,它可以为您设置诸如系统之类的东西。
它也比以前的系统更灵活,一旦你掌握了它,你就可以为你域中的任何类型的资源添加角色。
class User < ActiveRecord::Base
rolify
resourcify
end
---
the_boss = User.find(1)
bob = User.find_by(name: 'Bob')
# creating roles
the_boss.add_role(:manager) # add a global role
the_boss.add_role(:manager, bob) # add a role scoped to a user instance
# querying roles
bob.has_role?(:manager) # => false
the_boss.has_role?(:manager) # => true
the_boss.has_role?(:manager, bob) # => true
the_boss.has_role?(:manager, User.create) # => false
如果您使用 Rolify,请使用 Pundit 或 CanCanCan 等授权库来补充它以执行规则。