Ruby on rails 双重自指模型

Ruby on rails 双重自指模型,ruby-on-rails,postgresql,Ruby On Rails,Postgresql,考虑到基于遗传学的建模,单个模型旨在与postgresql具有两组自参考关系 “家长路线”相当直截了当 class Parent < ApplicationRecord belongs_to :parent_gestator, class_name: 'Individual' belongs_to :parent_nongestator, class_name: 'Individual' end class Individual < ApplicationRecord

考虑到基于遗传学的建模,单个模型旨在与postgresql具有两组自参考关系

“家长路线”相当直截了当

class Parent < ApplicationRecord
  belongs_to :parent_gestator, class_name: 'Individual'
  belongs_to :parent_nongestator, class_name: 'Individual'
end

class Individual < ApplicationRecord
  has_many :parent_gestators, foreign_key: :parent_gestator_id, class_name: 'Parent'
  has_many :parent_nongestators, foreign_key: :parent_nongestator_id, class_name: 'Parent'
  has_many :children, through: :parent_gestators
  has_many :children, through: :parent_nongestators
end
类父级
注:has_many关系允许多个父母通过血缘关系或领养关系

问题是“如何建立第二个自我参照,即配偶关系的自我参照”?。i、 e.两个个体的结合,没有父母(因此也没有兄弟姐妹)关系。 经过几次推理得出了一个非常简洁的定义

class Individual < ApplicationRecord
  has_many :spouses, foreign_key: :spouse_id, class_name: 'Individual'
end
class-Individual

然而,有一种烦人的感觉,这是不正确的/不完整的。上述是否正确/充分?

对我来说,拥有一个显式父类似乎有点不吉利,因为它需要一个存在成为两个模型的记录,例如,当它有父类和子类时。我会将模型重构成这样:

class Individual < ActiveRecord::Base

  class Relationship < ActiveRecord::Base
    self.table_name = 'relationships'

    class ParentChild < Relationship
      belongs_to :parent,
                 class_name: 'Individual',
                 foreign_key: :individual_1_id
      belongs_to :child,
                 class_name: 'Individual',
                 foreign_key: :individual_2_id
    end

    class Marriage < Relationship
      belongs_to :spouse_1,
                 class_name: 'Individual',
                 foreign_key: :individual_1_id
      belongs_to :spouse_2,
                 class_name: 'Individual',
                 foreign_key: :individual_2_id
    end

  end

  def children
    children_relationships.map{ |rel| rel.child }
  end

  def children_relationships
    Relationship::ParentChild.where(parent: self)
  end

  def spouses
    spouse_relationships.map do |rel|
      rel.spouse_1 == self ? rel.spouse_2 : rel.spouse_1
    end
  end

  def spouse_relationships
    clause = "individual_1_id = #{self.id} OR individual_2_id = #{self.id}")
    Relationship::Marriage.where clause
  end

  def parent_relationships
    Relationship::ParentChild.where(child: self)
  end

  def parents
    parent_relationships.map{ |rel| rel.parent }
  end

end
然后,用法很简单:

father = Individual.create(name: 'John')
=> #<Individual id: 7, name: "John"> 

mother = Individual.create(name: 'Jane')
=> #<Individual id: 8, name: "Jane">

Individual::Relationship::Marriage.create(spouse_1: father, spouse_2: mother)
=> #<Individual::Relationship::Marriage individual_1_id: 7, ...>

father.spouses
=> [#<Individual id: 8, name: "Jane">]

child_1 = Individual.create(name: 'Tom')
#<Individual id: 9, name: "Tom">

Individual::Relationship::ParentChild.create(parent: father, child: child_1)
Individual::Relationship::ParentChild.create(parent: mother, child: child_1)

child_1.parents
=> [#<Individual id: 7, name: "John">, #<Individual id: 8, name: "Jane">]
father=Individual.create(名字:'John')
=> # 
母亲=个人。创建(名称:“Jane”)
=> #
个人::关系::婚姻。创建(配偶1:父亲,配偶2:母亲)
=> #
父亲、配偶
=> [#]
child_1=个人。创建(名称:“Tom”)
#
个人::关系::ParentChild.create(父:父,子:子1)
个人::关系::ParentChild.create(父:母,子:子1)
儿童家长
=> [#, #]
当然,如果愿意,可以解调这些类。我喜欢嵌套类,因为它们向
Relationship
传递意义,并且您可以在其他实体之间建立其他类型的关系,而不会在顶级名称空间中产生概念冲突

另一种方法是用婚姻和配偶之间的全面的1:n关系,即个人关系,来取代这些丑陋的个人身份证。这将为三方联姻和Rails复杂的
接受
机制的嵌套属性打开大门。我没有时间完成这项工作,但如果可以,请发布你的结果


我想从这里,你可以进一步充实它!如果有任何问题,请告诉我。

此答案不直接回答上述问题

在处理这一问题时,一对或多个认识走到了最前沿。
a) 对于嵌套类有一个很好的观点。当处理不是数据表对象的推断类时,尤其是当它们的含义几乎完全与主模型关联时,嵌套更有意义(我发现这一点,因为在文档分离的情况下,这两个类之间存在看不见的间隙)
b) 基本逻辑有些复杂,但主要不反映现实。鉴于这是遗传学,有亲生父母(可能还有其他人),到此为止。因此,一个拥有自己表的主类将引用个人

belongs_to :biological_mother, foreign_key: :biological_mother_id, class_name: 'Individual'
belongs_to :biological_father, foreign_key: :biological_father_id, class_name: 'Individual'
(然后,生物结合可以在实践中通过父母和个人来增强)

然后是有亲生父母的个体班级

belongs_to :union

has_many :children_of_father, foreign_key: :biological_father_id, class_name: 'Union'
has_many :children_of_mother, foreign_key: :biological_mother_id, class_name: 'Union'
对联合体和子体的多个引用简洁地定义为

def biological_unions
  Union.where('biological_father_id = ? OR biological_mother_id = ?', self.id, self.id).all
end

def children
  union_ids = Union.where('biological_father_id = ? OR biological_mother_id = ?', self.id, self.id).pluck(:id)
  children = Individual.where('union_id IN (?)', union_ids)
end

5个建模语句,2个方法。

[许多fodd供思考解包]我不确定嵌套类与两个类相比有什么好处;db表仍然是唯一的。这可能是一个偏好的问题。我的问题是
属于
子类,因为它不允许多对多关系(想想收养、不确定的父母……)。整个过程让我对最初的设想产生了疑问。最好有一个工会类来处理一系列边缘案件(一夫多妻制、一夜情、秘密生活……),这对个人类来说并不方便。至于个人是婚姻的配偶1或配偶2的问题,我的观点是,一个联合类的目的是专门应用于一个血系(2个具有m/f属性的个体),任何其他对该联合有“贡献”的个体都将是联合类的一个子类。@Jerome你说得对,这是一个品味问题,如何构建你的模型及其关系。当我试图提出解决方案时,我只是按照自己的喜好。剩下的建议是用成熟的类来模拟个体之间的关系,而不是像has\u many那样的Rails魔术方法。你考虑组建一个
工会
班对我来说很合理。也就是说,我目前看不到我能进一步提供什么帮助。随时更新OP或添加更多评论。如果你通知我,我会回来看看我能做什么。
def biological_unions
  Union.where('biological_father_id = ? OR biological_mother_id = ?', self.id, self.id).all
end

def children
  union_ids = Union.where('biological_father_id = ? OR biological_mother_id = ?', self.id, self.id).pluck(:id)
  children = Individual.where('union_id IN (?)', union_ids)
end