Compréhension: option source de has_one / has_many dans Rails

Aidez-moi à comprendre l’option :source de has_one/has_many :through association. L’explication de l’API Rails n’a guère de sens pour moi.

“Spécifie le nom de l’association source utilisé par has_many :through => :queries . Utilisez-le uniquement si le nom ne peut être déduit de l’association. has_many :subscribers, :through => :subscriptions rechercheront :subscribers ou :subscriber sur Subscription , sauf si une :source est donnée. ”

Parfois, vous souhaitez utiliser des noms différents pour différentes associations. Si le nom que vous souhaitez utiliser pour une association sur le modèle n’est pas le même que celui du modèle :through , vous pouvez utiliser :source pour le spécifier.

Je ne pense pas que le paragraphe ci-dessus soit beaucoup plus clair que celui des docs, alors voici un exemple. Supposons que nous avons trois modèles, Pet , Dog and Dog::Breed .

 class Pet < ActiveRecord::Base has_many :dogs end class Dog < ActiveRecord::Base belongs_to :pet has_many :breeds end class Dog::Breed < ActiveRecord::Base belongs_to :dog end 

Dans ce cas, nous avons choisi de nommer le Dog::Breed , car nous voulons accéder à Dog.find(123).breeds comme une association agréable et pratique.

Maintenant, si nous voulons maintenant créer un has_many :dog_breeds, :through => :dogs association de has_many :dog_breeds, :through => :dogs sur Pet , nous avons soudainement un problème. Rails ne pourra pas trouver une association :dog_breeds sur Dog , donc Rails ne peut pas savoir quelle association de Dog vous souhaitez utiliser. Entrez :source :

 class Pet < ActiveRecord::Base has_many :dogs has_many :dog_breeds, :through => :dogs, :source => :breeds end 

Avec :source , nous demandons à Rails de rechercher une association appelée :breeds sur le modèle Dog (comme c'est le modèle utilisé pour les :dogs ), et l'utiliser.

Permettez-moi de développer cet exemple:

 class User has_many :subscriptions has_many :newsletters, :through => :subscriptions end class Newsletter has_many :subscriptions has_many :users, :through => :subscriptions end class Subscription belongs_to :newsletter belongs_to :user end 

Avec ce code, vous pouvez faire quelque chose comme Newsletter.find(id).users pour obtenir une liste des abonnés à la newsletter. Mais si vous voulez être plus clair et pouvoir taper Newsletter.find(id).subscribers place, vous devez remplacer la classe Newsletter par ceci:

 class Newsletter has_many :subscriptions has_many :subscribers, :through => :subscriptions, :source => :user end 

Vous renommez l’association d’ users en subscribers . Si vous ne fournissez pas la :source , Rails recherchera une association appelée subscriber dans la classe d’abonnement. Vous devez lui dire d’utiliser l’association d’ user dans la classe d’abonnement pour faire la liste des abonnés.

La réponse la plus simple:

Est le nom de la relation dans la table au milieu.