Comprensione: opzione sorgente di has_one / has_many tramite Rails


184

Per favore aiutami a capire l' :sourceopzione di has_one/has_many :throughassociazione. La spiegazione dell'API di Rails non ha molto senso per me.

"Specifica il nome dell'associazione di origine utilizzato da has_many :through => :queries. Utilizzarla solo se il nome non può essere dedotta dalla dell'associazione. has_many :subscribers, :through => :subscriptionsCercherà sia :subscriberso :subscribersu Subscription, a meno che una :sourceè dato."

Risposte:


238

A volte, si desidera utilizzare nomi diversi per associazioni diverse. Se il nome che si desidera utilizzare per un'associazione sul modello non è lo stesso dell'associazione sul :throughmodello, è possibile utilizzare :sourceper specificarlo.

Non penso che il paragrafo sopra sia molto più chiaro di quello nei documenti, quindi ecco un esempio. Supponiamo che abbiamo tre modelli, Pet, Doge 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

In questo caso, abbiamo scelto lo spazio dei nomi Dog::Breed, perché vogliamo accedere Dog.find(123).breedscome associazione piacevole e conveniente.

Ora, se ora vogliamo creare has_many :dog_breeds, :through => :dogsun'associazione Pet, improvvisamente abbiamo un problema. Rails non sarà in grado di trovare :dog_breedsun'associazione Dog, quindi Rails non può sapere quale Dog associazione desideri utilizzare. Inserisci :source:

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

Con :source, stiamo dicendo a Rails di cercare un'associazione chiamata :breedssul Dogmodello (dato che è il modello utilizzato :dogs) e di usarla.


2
Penso che volevi che la tua ultima classe Animal fosse chiamata classe Pet, credo solo un refuso.
Kamilski81,

3
Nell'esempio sopra, l'associazione sotto Dogdovrebbe essere has_many :breedinvece di :breedse quindi :sourceessere :breedsingolare, per rappresentare il nome del modello, anziché :breedsquale rappresenta il nome della tabella? Ad esempio has_many :dog_breeds, :through => :dogs, :source => :breed(nessun ssuffisso :breed)?
LazerSharks il

1
Ho provato questo. è singolare, nessun ssuffisso in:source =>
Anwar

"In questo caso, abbiamo scelto lo spazio dei nomi di Dog :: Breed, perché vogliamo accedere a Dog.find (123) .breeds come associazione piacevole e conveniente.". Non hai bisogno di uno spazio dei nomi per quello vero?
Jwan622,

201

Vorrei espandere questo esempio:

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

Con questo codice, puoi fare qualcosa di simile Newsletter.find(id).usersper ottenere un elenco degli iscritti alla newsletter. Ma se vuoi essere più chiaro ed essere in grado di digitare Newsletter.find(id).subscribers, devi cambiare la classe Newsletter in questo modo:

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

Stai rinominando l' usersassociazione in subscribers. Se non lo fornisci :source, Rails cercherà un'associazione chiamata subscribernella classe Subscription. Devi dirlo per usare l' userassociazione nella classe Subscription per fare la lista degli iscritti.


2
si noti che i nomi dei modelli singularize dovrebbero essere usati :source =>, non al plurale. Quindi, :usersè sbagliato, :userè corretto
Anwar,

Questa è la risposta migliore !, vorrei solo sottolineare questa parte: "Stai rinominando l'associazione degli utenti in abbonati. Se non fornisci: source, Rails cercherà un'associazione chiamata abbonato nella classe Abbonamento".
Brian Joseph Spinos,

11

La risposta più semplice:

È il nome della relazione nella tabella nel mezzo.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.