2008-11-21 119 views
47

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

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 

是否有与2个外键使用的has_many,或者可能改变基于对象的性别外键的简单方法?或者还有其他更好的方法吗?

谢谢!

+0

对于Rails 3中,范围chainning,ActiveRecord的::关系,并最终`has_many`:http://stackoverflow.com/questions/17476521/rails-has-many-custom-activerecord-association/17476639#17476639 – MrYoshiji 2013-07-04 19:02:21

+0

你是寻找“组合键”:http:// stackoverflow。com/questions/17882105/is-it-it-possible-to-define-composite-primary-key-for-table-using-active-record – xpepermint 2014-02-27 12:53:13

回答

43

发现IRC上一个简单的答案,似乎工作(感谢雷达):

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 
+20

但#children返回数组... – 2011-11-24 21:28:09

+1

如果有任何默认范围,特别是那些可能影响结果顺序的范围,则此解决方案将不起作用,因为结果不会按预期排序。 – mgadda 2012-08-09 17:54:43

8

我相信你可以实现你想使用的关系: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 

我会在下班后确认并编辑此答案; )

+0

这不适合我...似乎很好,但是,我得到了`has_many`关系的预期错误:'people`表中没有名为`person_id`的列。 – deivid 2014-02-21 10:48:06

8

使用在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 
4

我更喜欢使用范围为这个问题。就像这样:

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 
17

为了改善Kenzie的回答,您可以实现一个ActiveRecord关系定义Person#children,如:

def children 
    children_of_mother.merge(children_of_father) 
end 

看到this answer更多细节

3

不是解决所述的一般问题(“有多个外键的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 
2

我一直在寻找相同的功能,如果你不想返回一个数组而不是ActiveRecord::AssociationRelation,你可以使用<<而不是+。 (See the ActiveRecord documentation

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 
2

我的回答Associations and (multiple) foreign keys in rails (3.2) : how to describe them in the model, and write up migrations是只为你!

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

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 

所以什么问题吗?