Понимание: исходная опция has_one / has_many через Rails - PullRequest
170 голосов
/ 08 января 2011

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

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

Ответы [ 3 ]

217 голосов
/ 08 января 2011

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

184 голосов
/ 08 января 2011

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

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

9 голосов
/ 20 апреля 2017

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

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

...