Розуміння: вихідний параметр has_one / has_many через Rails


184

Будь ласка, допоможіть мені зрозуміти :sourceваріант has_one/has_many :throughасоціації. Пояснення API Rails має для мене дуже мало сенсу.

"Вказує ім'я асоціації джерела, яке використовує has_many :through => :queries. Використовуйте його лише в тому випадку, якщо ім'я не можна зробити з асоціації. Шукати has_many :subscribers, :through => :subscriptionsбуде :subscribersабо :subscriberна Subscription, якщо :sourceне вказано а."

Відповіді:


238

Іноді для різних асоціацій потрібно використовувати різні назви. Якщо ім'я, яке ви хочете використовувати для асоціації на моделі, не збігається з асоціацією на :throughмоделі, ви можете :sourceвказати її.

Я не думаю, що наведений вище абзац є набагато зрозумілішим, ніж той у документах, ось ось приклад. Припустимо, у нас є три моделі Pet, Dogі 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

У цьому випадку ми вибрали простір імен Dog::Breed, тому що ми хочемо отримати доступ Dog.find(123).breedsяк приємна та зручна асоціація.

Якщо зараз ми хочемо створити has_many :dog_breeds, :through => :dogsасоціацію Pet, у нас раптом виникає проблема. Rails не зможе знайти :dog_breedsасоціацію Dog, тому Rails не може знати, яку Dog асоціацію ви хочете використовувати. Введіть :source:

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

З :source, ми говоримо Rails , щоб шукати асоціацію під назвою :breedsна Dogмоделі (як це використовується модель :dogs), і використовувати це.


2
Я думаю, що ти мав на увазі для свого останнього класу Тварину називати вихованцем класу, я просто вірю.
Kamilski81

3
У наведеному вище прикладі, чи повинна асоціація під Dogбути has_many :breedзамість, :breedsа потім :sourceбути :breedодниною, щоб представляти ім'я моделі, замість :breedsякої представляє ім’я таблиці? Наприклад has_many :dog_breeds, :through => :dogs, :source => :breed(без sсуфікса :breed)?
LazerSharks

1
Я це перевірив. вона є одниною, без sсуфікса в:source =>
Anwar

"У цьому випадку ми вибрали простір імен Dog :: Порода, оскільки ми хочемо отримати доступ до Dog.find (123) .breeds як приємна та зручна асоціація." Для цього вам не потрібен простір імен?
Jwan622

201

Дозвольте розширити цей приклад:

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

За допомогою цього коду ви можете зробити щось на кшталт Newsletter.find(id).usersотримання списку передплатників інформаційного бюлетеня. Але якщо ви хочете зробити більш зрозумілим і мати можливість набрати Newsletter.find(id).subscribersнатомість, ви повинні змінити клас розсилки на це:

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

Ви перейменуєте usersасоціацію в subscribers. Якщо ви не надаєте :source, Rails шукатиме асоціацію, яка називається subscriberв класі підписки. Ви повинні сказати йому, щоб використовувати userасоціацію в класі передплати, щоб скласти список підписників.


2
зауважимо, що назви моделей синдуляризації повинні використовуватися в :source =>, а не в множині. Отже, :usersпомиляється, :userправильно
Анвар

Це найкраща відповідь! Дозвольте мені лише наголосити на цій частині: "Ви перейменовуєте асоціацію користувачів на передплатників. Якщо ви не надаєте: джерело, Rails шукатиме асоціацію, яка називається підписником у класі підписки".
Брайан Джозеф Спінос

11

Найпростіша відповідь:

Чи називається співвідношення у таблиці в середині.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.