2016-03-23 54 views
0

我已经看过这个SO question,但我仍然无法绕开这个概念。ActiveRecord has_many和belongs_to在相同的模型

我有一个类似的设置与链接的SO问题,因为我有一个User类包含员工和经理。我还有Role(拥有角色名称)和UserRole(拥有哪个用户具有哪个角色)的另一个模型。

我的要求规定,一个Employee(一UserRoleUser)只能有一个管理器(一个UserRoleManager)。现在,这个管理概念是对当前系统的补充,我不应该更改users表,所以我正在用他们自己的MVC创建一个新表。

但现在我发现很难使用has_manybelongs_to就像链接的问题。我如何使用新模型?我尝试使用:through,但它不起作用(出于某种原因)。

我做错了吗?我是否应该只添加manager_id列到users并将链接问题中的解决方案应用到我的问题中?另外,如何确保只有一个UserRoleManager可以设置为管理器?我不得不说,我相对比较新的Rails和ActiveRecord,甚至一般的Ruby。

注2:如果相关,我使用Rails 4.2.0。

回答

0

一个多设置了许多系统的作用是非常直截了当:

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_idusers和设置自引用一个添加到一对多的关系:

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的优秀宝石,它为您提供了诸如系统等。

它还比以前的系统更灵活,一旦你掌握了它,你可以添加角色到你的域中的任何类型的资源。

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与授权库,如权威人士或CanCanCan执行这些规则恭维。

+0

我不应该编辑'users'表,但如果另一个选项添加另一个gem,也许一个新的列并不是一个坏主意。 – StorymasterQ

+0

我想我要用'manager_id'列。如何获取新插入的管理员的错误消息名称?编辑:没关系,我想出了'manager.name'。 – StorymasterQ

+0

“添加另一颗宝石”并不总是一件坏事。不要因为担心技术部门或不在这里发明综合症而重新发明轮子。 – max

0
class User < ActiveRecord::Base 
    belongs_to :manager, class_name: 'User' 
    has_many :employees, foreign_key: :manager_id, class_name: 'User' 
end 

它有帮助吗?

更新:

class User < ActiveRecord::Base 
    has_one :role, through: :user_role 
    belongs_to :manager, -> { where(role: {name: 'manager'}), class_name: 'User' 
    has_many :employees, -> { where(role: {name: 'employee'}), foreign_key: :manager_id, class_name: 'User' 
end 
+0

这是链接问题的解决方案,但我无法使其工作。我如何将新表放入关联中? – StorymasterQ

+0

这次更新如何?不知道这是你想要完成的,但你也许应该看看这种结构。 –

+0

嗯,所以我应该/必须在'users'表中添加一个'manager_id'列? – StorymasterQ

相关问题