Понимание: исходная опция has_one/has_many через Rails

Пожалуйста, помогите мне в понимании опции :source ассоциации has_one/has_many :through. Объяснение API Rails очень мало для меня.

"Задает имя ассоциации источника, используемое has_many :through => :queries. Используйте его только в том случае, если имя не может быть выведено из ассоциация. has_many :subscribers, :through => :subscriptions будет найдите :subscribers или :subscriber на Subscription, если не указано a :source."

Ответ 1

Иногда вы хотите использовать разные имена для разных ассоциаций. Если имя, которое вы хотите использовать для ассоциации в модели, не совпадает с ассоциацией в модели :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

Позвольте мне расширить этот пример:

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 вместо этого, вы должны изменить класс Newsletter следующим образом:

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

Вы переименовываете ассоциацию users в subscribers. Если вы не предоставляете :source, Rails будет искать ассоциацию с именем subscriber в классе Subscription. Вы должны сказать ему, чтобы использовать ассоциацию user в классе Subscription для составления списка подписчиков.

Ответ 3

Самый простой ответ:

Является ли имя отношения в таблице посередине.