Memahami: opsi sumber has_one / has_many melalui Rails

184

Tolong bantu saya dalam memahami :sourceopsi has_one/has_many :throughasosiasi. Penjelasan Rails API sangat tidak masuk akal bagi saya.

"Menentukan nama asosiasi sumber yang digunakan oleh has_many :through => :queries. Hanya gunakan itu jika nama tidak dapat disimpulkan dari asosiasi. has_many :subscribers, :through => :subscriptionsAkan mencari salah satu :subscribersatau :subscriberpada Subscription, kecuali a :sourcediberikan."

Tri Vuong
sumber

Jawaban:

238

Terkadang, Anda ingin menggunakan nama yang berbeda untuk asosiasi yang berbeda. Jika nama yang ingin Anda gunakan untuk asosiasi pada model tidak sama dengan asosiasi pada :throughmodel, Anda bisa menggunakan :sourceuntuk menentukannya.

Saya tidak berpikir paragraf di atas jauh lebih jelas daripada paragraf di dokumen, jadi inilah contohnya. Mari kita asumsikan kita memiliki tiga model Pet,, Dogdan 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

Dalam hal ini, kami telah memilih untuk namespace Dog::Breed, karena kami ingin mengakses Dog.find(123).breedssebagai asosiasi yang bagus dan nyaman.

Sekarang, jika kita sekarang ingin membuat has_many :dog_breeds, :through => :dogsasosiasi Pet, kita tiba-tiba memiliki masalah. Rails tidak akan dapat menemukan :dog_breedsasosiasi Dog, jadi Rails tidak mungkin tahu asosiasi mana yang Dog ingin Anda gunakan. Masukkan :source:

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

Dengan :source, kami memberi tahu Rails untuk mencari asosiasi yang dipanggil :breedspada Dogmodel (seperti itulah model yang digunakan :dogs), dan gunakan itu.

vonconrad
sumber
2
Saya pikir Anda bermaksud untuk hewan kelas terakhir Anda disebut Pet kelas, hanya salah ketik saya percaya.
Kamilski81
3
Dalam contoh di atas, seharusnya asosiasi di bawah Dogmenjadi has_many :breedbukan :breedsdan kemudian :sourceakan :breedtunggal, untuk mewakili nama model, bukan :breedsyang mewakili nama tabel? Misalnya has_many :dog_breeds, :through => :dogs, :source => :breed(tanpa ssuffixing :breed)?
LazerSharks
1
Saya sudah menguji ini. itu tunggal, tidak ada sakhiran di:source =>
Anwar
"Dalam hal ini, kami telah memilih untuk namespace Dog :: Breed, karena kami ingin mengakses Dog.find (123). Breeds sebagai asosiasi yang baik dan nyaman.". Anda tidak perlu namespace untuk itu kan?
Jwan622
201

Biarkan saya memperluas contoh itu:

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

Dengan kode ini, Anda dapat melakukan sesuatu seperti Newsletter.find(id).usersmendapatkan daftar pelanggan buletin. Tetapi jika Anda ingin lebih jelas dan bisa mengetik Newsletter.find(id).subscribers, Anda harus mengubah kelas Newsletter menjadi ini:

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

Anda mengganti nama usersasosiasi menjadi subscribers. Jika Anda tidak menyediakan :source, Rails akan mencari asosiasi yang disebut subscriberdalam kelas Berlangganan. Anda harus mengatakannya untuk menggunakan userasosiasi di kelas Berlangganan untuk membuat daftar pelanggan.

Jeremy Ruten
sumber
2
perhatikan bahwa, nama model singularisasi harus digunakan :source =>, bukan jamak. Jadi, :usersitu salah, :userbenar
Anwar
Ini adalah jawaban terbaik !, saya tekankan saja bagian ini: "Anda mengganti nama asosiasi pengguna menjadi pelanggan. Jika Anda tidak memberikan: source, Rails akan mencari asosiasi yang disebut pelanggan di kelas Berlangganan."
Brian Joseph Spinos
11

Jawaban paling sederhana:

Adalah nama hubungan di tabel di tengah.

Dreeub
sumber