两种模式组织和用户具有1:多关系,其中组织有多个用户(成员;用户也可以不与任何组织关联):
class Organization < ActiveRecord::Base
has_many :users, dependent: :destroy
accepts_nested_attributes_for :users, :reject_if => :all_blank, :allow_destroy => true
validates_associated :users
end
class User < ActiveRecord::Base
belongs_to :organization, inverse_of: :users
end
一切正常,各种测试都通过了 现在我为主持人功能添加了一个额外的关系,其中用户可以拥有(多个)组织的主持人权限。因此,通过第三个模型建立了很多:很多关系,我将其命名为主持人:
class Organization < ActiveRecord::Base
has_many :users, dependent: :destroy
accepts_nested_attributes_for :users, :reject_if => :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
我故意使用reviewer
和reviewee
名称。如果我只是在主持人模型中使用user_id
和organization_id
,我可能会搞砸了。因为如果您要引用@user.organization
,那么就不能定义要使用哪种关系。它会使用用户和组织之间的1:多关系,还是许多关系:很多通过关系......?通过对许多人使用不同的名称:很多通过关系,@user.organization
应该引用1:many关系,而@user.reviewee
例如应该引用许多:很多通过关系。
然而,在实施之后,突然间各种测试都失败了。例如:我有一个表单,为组织注册一个额外的用户。 Clicing a按钮将organization_id传递给要为其创建其他用户的表单。现在突然这个ID没有被传递到表单,我得到了所有nil
错误,因为组织没有被定义(即使链接仍然是例如url/member?organization_id=43
)。我可以提供更多的例子。
因为新关系似乎存在某种冲突。也许它无法理解何时使用许多:很多通过关系和1:多关系时,即使我使用了差异审阅者和审稿人姓名...... 我是否错误地建模或者不可能有两个两个相同模型之间的不同关系?
如果我从组织模型中删除第二条has_many :users
行,则所有测试都会再次通过。所以问题似乎是我有两次这种关系。
答案 0 :(得分:1)
处理此问题的一个好的和常见的模式称为资源范围角色。
用户可以拥有许多角色(父亲,母亲,主持人,草裙舞等),在某些情况下,角色的范围限定为特定资源。就像父亲/母亲的范围是用户(孩子)或主持人可以限定论坛。
拥有像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类 - 而不仅仅是组织。更好的是,有很多宝石可以提供这种功能,例如Months。