Bon voici un bon cas bien complexe de relation à gérer avec rubyonrails 3 et ActiveRecord :
Le but est de représenter les relations familiales (family_relationship) de personne (contact).
- Table contacts (qui représente un être humain avec ses coordonnées).
- Table family_relationships (qui représente une relation entre deux êtres humains, lien de père, mère, frère, soeur), avec deux clés étrangères qui pointent vers contacts : master_id et slave_id et un champ type (integer : 1 : fils, 2 : fille, 3 : père, 4 : mère).
On lit la relation comme suit : Master a pour {père|mère|fils|fille} slave.
Nous voulons pouvoir faire :
contact.fathers
=> [#<Contact id: 7.....>]
contact.mothers
=> [#<Contact id: 9.....>]
contact.daughters
=> [#<Contact id: 11.....>, #<Contact id: 8......> ]
contact.sons
=> [#<Contact id: 12.....>, #<Contact id: 13......> ]
Ici on ne s'occupera pas de gérer la contrainte UN SEUL père et UNE SEULE mère.
Voici comment définir nos models :
Ici le model Contact
class Contact < ActiveRecord::Base has_many :family_relationship_as_masters, :foreign_key => "master_id", :class_name => "FamilyRelationship" has_many :family_relationship_as_slaves, :foreign_key => "slave_id", :class_name => "FamilyRelationship" has_many :sons, :through => :family_relationship_as_masters, :source => :slave, :conditions => ['"family_relationships"."type_relationship" = ?',1] has_many :daughters, :through => :family_relationship_as_masters, :source => :slave, :conditions => ['"family_relationships"."type_relationship" = ?',2] has_many :fathers, :through => :family_relationship_as_masters, :source => :slave, :conditions => ['"family_relationships"."type_relationship" = ?',3] has_many :mothers, :through => :family_relationship_as_masters, :source => :slave, :conditions => ['"family_relationships"."type_relationship" = ?',4] end
Et là le model FamilyRelationship
class FamilyRelationship < ActiveRecord::Base belongs_to :master, :foreign_key => "master_id", :class_name => "Contact" belongs_to :slave, :foreign_key => "slave_id", :class_name => "Contact" end
Je crois qu'il s'agit de la relation la plus compliquée que j'ai faite dans une application RubyOnRails (enfin qui utilise de plus d'options aux méthodes de jointure has_many et belongs_to en tout cas)