2008-11-21 117 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 

所以什麼問題嗎?