Модель Rails has_many с несколькими foreign_keys
Относительно новый для рельсов и попытка моделировать очень простое семейное "дерево" с одной моделью Person, которая имеет имя, пол, father_id и mother_id (2 родителя). Ниже в основном то, что я хочу сделать, но, очевидно, я не могу повторить: children в 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 внешними ключами или, возможно, изменить внешний ключ на основе пола объекта? Или есть другой/лучший способ вообще?
Спасибо!
Ответы
Ответ 1
Нашел простой ответ на 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
Ответ 2
Чтобы улучшить ответ Kenzie, вы можете достичь отношения ActiveRecord, определяя Person#children
как:
def children
children_of_mother.merge(children_of_father)
end
см. этот ответ для более подробной информации
Ответ 3
Я считаю, что вы можете достичь отношений, которые хотите использовать: 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
Я подтвержу и отредактирую этот ответ после работы; )
Ответ 4
Используется 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
Ответ 5
Я предпочитаю использовать области для этой проблемы. Вот так:
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
Ответ 6
Не решение общего вопроса, как указано ( "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
Ответ 7
Я искал одну и ту же функцию, если вы не хотите возвращать массив, но 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
Ответ 8
Мой ответ на Ассоциации и (несколько) внешних ключей в рельсах (3.2): как их описать в модели и записать миграции - это только для вас!
Что касается вашего кода, вот мои модификации
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
Итак, любые вопросы?