Modèle Rails has_many avec plusieurs étrangers_keys

Relativement nouveau pour les rails et essayant de modéliser une famille très simple “arbre” avec un seul modèle de personne qui a un nom, un sexe, père_id et mother_id (2 parents). Voici en gros ce que je veux faire, mais évidemment, je ne peux pas répéter: les enfants dans un has_many (le premier est écrasé).

class Person  '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 

Existe-t-il un moyen simple d’utiliser has_many avec 2 clés étrangères, ou peut-être de changer la clé étrangère en fonction du genre de l’object? Ou existe-t-il une autre solution / meilleure?

Merci!

J’ai trouvé une réponse simple sur IRC qui semble fonctionner (grâce à 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 

Pour améliorer la réponse de Kenzie , vous pouvez obtenir une Relation ActiveRecord en définissant Person#children comme:

 def children children_of_mother.merge(children_of_father) end 

voir cette réponse pour plus de détails

Je crois que vous pouvez réaliser les relations que vous voulez en utilisant: 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 

Je vais confirmer et éditer cette réponse après le travail; )

Pour cela, utilisez named_scopes sur le modèle 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 

Je préfère utiliser les étendues pour ce problème. Comme ça:

 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 

Cette astuce facilite l’access des enfants sans instances d’utilisation:

 Person.children_for father_id, mother_id 

Pas une solution à la question générale telle qu’énoncée (“has_many avec plusieurs clés étrangères”), mais, étant donné qu’une personne peut être une mère ou un père, mais pas les deux, j’appendais une colonne sur le gender et

  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 

Je cherchais la même fonctionnalité, si vous ne voulez pas renvoyer un tableau mais un ActiveRecord::AssociationRelation , vous pouvez utiliser << au lieu de + . ( Voir la documentation 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 

Ma réponse aux associations et aux (multiples) clés étrangères dans les rails (3.2): comment les décrire dans le modèle et écrire les migrations est fait pour vous!

En ce qui concerne votre code, voici mes modifications

 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 

Donc des questions?