2008-11-21 3 views
47

Относительно новый для рельсов и пытается смоделировать очень простое семейное «дерево» с одной моделью Person, которая имеет имя, пол, father_id и mother_id (2 родителя). Ниже в основном то, что я хочу сделать, но, очевидно, я не могу повторить: дети в has_many (первый из них перезаписывается).Rails Model 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 

Есть простой способ использовать has_many с 2-мя внешними ключами, или, возможно, изменить внешний ключ по половому признаку объекта? Или есть другой/лучший способ?

Спасибо!

+0

Для Rails 3, scope 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-possible-to-define-composite-primary-key-for-table-using-active-record – xpepermint 2014-02-27 12:53:13

ответ

43

Нашел простой ответ на IRC, который, кажется, работает (спасибо Radar):

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

, но # дети возвращают массив ... – 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

Это не сработало для меня ... казалось, что это правда, но Я получил ожидаемый erorr для отношений `has_many`: no столбец с именем` person_id` в таблице `people`. – deivid 2014-02-21 10:48:06

8

Подержанного named_scopes по сравнению с моделью Person сделать это:

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 «s, вы можете достичь Relation 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 

Так какие вопросы?

Смежные вопросы