Понимание: исходная опция 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
Самый простой ответ:
Является ли имя отношения в таблице посередине.