Понимание: исходный вариант has_one / has_many через Rails

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

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


person trivektor    schedule 08.01.2011    source источник


Ответы (3)


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

person vonconrad    schedule 08.01.2011
comment
Думаю, вы имели в виду, что ваш последний класс Animal назывался class Pet, я считаю, это просто опечатка. - person Kamilski81; 29.02.2012
comment
В приведенном выше примере должна ли ассоциация в Dog быть has_many :breed вместо :breeds, а затем :source быть :breed в единственном числе, чтобы представлять название модели, вместо :breeds, которое представляет имя таблицы? Например. has_many :dog_breeds, :through => :dogs, :source => :breed (без s суффикса :breed)? - person LazerSharks; 31.12.2014
comment
Я это проверил. это единственное число, без суффикса s в :source => - person Anwar; 18.10.2015
comment
В этом случае мы выбрали пространство имен Dog :: Breed, потому что мы хотим получить доступ к Dog.find (123) .breeds как к красивой и удобной ассоциации ... Для этого вам не нужно пространство имен, не так ли? - person Jwan622; 10.11.2017

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

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 для создания списка подписчиков.

person Paige Ruten    schedule 08.01.2011
comment
обратите внимание, что имена моделей в единственном числе следует использовать в :source =>, а не во множественном числе. Итак, :users неверно, :user правильно - person Anwar; 18.10.2015
comment
Это лучший ответ !, позвольте мне просто подчеркнуть эту часть: вы переименовываете ассоциацию пользователей в подписчиков. Если вы не предоставите: source, Rails будет искать ассоциацию с именем subscriber в классе Subscription. - person Brian Joseph Spinos; 30.10.2017

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

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

person Dreeub    schedule 20.04.2017