Rails Model has_many与多个foreign_keys

相对较新的轨道,并试图build模一个非常简单的家庭“树”与单人模型,有一个名称,性别,father_id和mother_id(2父母)。 下面基本上是我想要做的,但显然我不能重复:has_many中的孩子(第一个被覆盖)。

class Person < ActiveRecord::Base belongs_to :father, :class_name => 'Person' belongs_to :mother, :class_name => 'Person' has_many :children, :class_name => 'Person', :foreign_key => 'mother_id' has_many :children, :class_name => 'Person', :foreign_key => 'father_id' end 

是否有一个简单的方法来使用has_many与2个外键,或者也许根据对象的性别更改外键? 还是有另外一个/更好的方法呢?

谢谢!

在IRC上find了一个简单的答案(感谢雷达):

 class Person < ActiveRecord::Base belongs_to :father, :class_name => 'Person' belongs_to :mother, :class_name => 'Person' has_many :children_of_father, :class_name => 'Person', :foreign_key => 'father_id' has_many :children_of_mother, :class_name => 'Person', :foreign_key => 'mother_id' def children children_of_mother + children_of_father end end 

为了改进Kenzie的答案,可以通过定义Person#children来实现ActiveRecord关系:

 def children children_of_mother.merge(children_of_father) end 

看到这个答案更多的细节

我相信你可以实现你想要使用的关系:has_one。

 class Person < ActiveRecord::Base has_one :father, :class_name => 'Person', :foreign_key => 'father_id' has_one :mother, :class_name => 'Person', :foreign_key => 'mother_id' has_many :children, :class_name => 'Person' end 

下class后我会确认并编辑这个答案。 )

在Person模型上使用named_scopes可以这样做:

 class Person < ActiveRecord::Base def children Person.with_parent(id) end named_scope :with_parent, lambda{ |pid| { :conditions=>["father_id = ? or mother_id=?", pid, pid]} } end 

我更喜欢使用范围来解决这个问题。 喜欢这个:

 class Person < ActiveRecord::Base belongs_to :father, :class_name => 'Person' belongs_to :mother, :class_name => 'Person' has_many :children_of_father, :class_name => 'Person', :foreign_key => 'father_id' has_many :children_of_mother, :class_name => 'Person', :foreign_key => 'mother_id' scope :children_for, lambda {|father_id, mother_id| where('father_id = ? AND mother_id = ?', father_id, mother_id) } end 

这个技巧可以让没有使用实例的孩子变得容易:

 Person.children_for father_id, mother_id 

不是所说的一般问题的解决scheme(“有多个外键的has_many”),但是,由于一个人既可以是母亲也可以是父亲,但不是两者,我会添加一个gender列,

  has_many :children_of_father, :class_name => 'Person', :foreign_key => 'father_id' has_many :children_of_mother, :class_name => 'Person', :foreign_key => 'mother_id' def children gender == "male" ? children_of_father : children_of_mother end 

我正在寻找相同的function,如果你不想返回一个数组,但是一个ActiveRecord::AssociationRelation ,你可以使用<<而不是+ 。 ( 请参阅ActiveRecord文档 )

 class Person < ActiveRecord::Base belongs_to :father, :class_name => 'Person' belongs_to :mother, :class_name => 'Person' has_many :children_of_father, :class_name => 'Person', :foreign_key => 'father_id' has_many :children_of_mother, :class_name => 'Person', :foreign_key => 'mother_id' def children children_of_mother << children_of_father end end 

我对rails(3.2)中的Associations和(multiple)外键的回答是:如何在模型中描述它们,写下迁移只是为了你!

至于你的代码,这里是我的修改

 class Person < ActiveRecord::Base belongs_to :father, :class_name => 'Person' belongs_to :mother, :class_name => 'Person' has_many :children, ->(person) { unscope(where: :person_id).where("father_id = ? OR mother_id = ?", person.id, person.id) }, class_name: 'Person' end 

那么有什么问题?