2011-01-08 2 views
138

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

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

ответ

178

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

Я думаю, что вы предназначались для вашего последнего класса Animal, которого можно назвать классом Pet, просто опечатка, которую я считаю. – Kamilski81

+0

Спасибо, хорошо поймать! – vonconrad

+2

В приведенном выше примере, если ассоциация под 'Dog' будет' has_many: breed' вместо ': breed'', а затем': source' be ': breed' singular, чтобы представить имя модели, а не': породы ", который представляет имя таблицы? Например. 'has_many: dog_breeds,: through =>: dogs,: source =>: breed' (no' s' suffixing ': breed')? – LazerSharks

152

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

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 в классе Subscription. Вы должны сказать ему, чтобы использовать ассоциацию user в классе Subscription для составления списка подписчиков.

+1

Спасибо.Намного понятнее – Anwar

+2

, обратите внимание, что имена имен в стиле «уникальность» должны использоваться в ': source =>', а не во множественном числе. Итак, ': users' не так,': пользователь' правильный – Anwar

+0

Это лучший ответ !, позвольте мне просто подчеркнуть эту часть: «Вы переименовываете ассоциацию пользователей для подписчиков. Если вы не предоставите источник: Rails будет искать ассоциацию, называемую подписчиком в классе Subscription. " –

5

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

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