建模相同模型之间的两种不同关系

两个模型组织和用户具有1:多关系,其中组织具有多个用户(成员;用户也可以与任何组织关联):

class Organization  :all_blank, :allow_destroy => true validates_associated :users end class User < ActiveRecord::Base belongs_to :organization, inverse_of: :users end 

一切正常,各种测试都通过了。
现在我为主持人function添加了一个额外的关系,其中用户可以拥有(多个)组织的主持人权限。 因此,通过第三个模型有很多:很多关系,我将其称为主持人:

 class Organization  :all_blank, :allow_destroy => true has_many :moderators, class_name: "Moderator", foreign_key: "reviewee_id", dependent: :destroy has_many :users, through: :moderators, source: :reviewer validates_associated :users end class User < ActiveRecord::Base belongs_to :organization, inverse_of: :users has_many :moderators, class_name: "Moderator", foreign_key: "reviewer_id", dependent: :destroy has_many :organizations, through: :moderators, source: :reviewee end class Moderator < ActiveRecord::Base belongs_to :reviewee, class_name: "Organization" belongs_to :reviewer, class_name: "User" end 

我故意使用reviewerreviewer名字。 如果我只是在主持人模型中使用user_idorganization_id ,我可能会搞砸了。 因为如果您将引用@user.organization则不会定义要使用的关系。 它会使用用户和组织之间的1:多关系,还是许多关系:很多通过关系……? 通过使用不同的名称:很多通过关系, @user.organization应该引用1:many关系,而@user.reviewee例如应该引用很多:很多通过关系。

然而,在实施之后,突然间各种测试都失败了。 例如:我有一个表单,为组织注册一个额外的用户。 通过clicing按钮将organization_id传递给要为其创建其他用户的表单。 现在突然这个id没有传递给表单,我得到所有nil错误,因为组织没有定义(即使链接仍然是例如url/member?organization_id=43 )。 我可以提供更多的例子。

因此,由于新的关系,似乎存在某种冲突。 也许它无法理解何时使用许多:很多通过关系和1:多关系时,即使我使用了差异审阅者和审稿人姓名…… 我是否错误地建模或者不可能有两种不同的关系2个相同的型号?

如果我从组织模型中删除第二个has_many :users行,则所有测试都会再次通过。 所以问题似乎是我有两次这种关系。

处理此问题的一种常见模式称为资源范围角色。

用户可以拥有许多角色(父亲,母亲,主持人,草裙舞等),在某些情况下,角色的范围限定为特定资源。 像父亲/母亲的范围是用户(孩子)或主持人可以作为论坛的范围。

具有“系统级”角色(如super-admin并非作用于资源也很常见。

 class User < ActiveRecord::Base has_many :roles scope :moderators, ->{ joins(:roles).where( roles: { name: 'moderator' } ) } belongs_to :organization end # columns: name:string, resource_id:int, resource_type:string, user_id:int class Role < ActiveRecord::Base belongs_to :user belongs_to :resource, polymorphic: true end class Organization < ActiveRecord::Base has_many :roles, as: :resource has_many :users # This is just a relationship to users with a scope has_many :moderators, -> { moderators }, class_name: 'User' end 

因此,要添加主持人,我们会这样做:

 organization = Organization.find(1) organization.roles.create(user: organization.users.find(1), name: 'moderator') 

要获得组织的所有主持人:

 moderators = Organization.find(1).moderators 

这里真棒的是我们可以在任何资源上使用我们的Role类 – 而不仅仅是组织。 更好的是有很多gem可以提供这种function,比如Rolify 。