Ответ 1
# 1
Banner.join(: banner_type) - генерирует NoMethodError: undefined метод "join" для # Почему нет метода Rails, называемого join, когда это имя метода SQL?
Яснее, когда вы читаете как простой английский, чтобы сказать, что "Баннер присоединяется к типу баннера" и "Баннер присоединиться к типу баннера". Я не уверен, что есть больше причин, чем это.
# 2
Почему я делаю Banner.joins(: banner_type), то есть особый параметр banner_type, когда имя таблицы - banner_types. Я не присоединяюсь к таблицам Banner и BannerType (которые обозначают Rails как множественное число). Если я попробую Banner.joins(: banner_types), это ошибка, которую я получаю:
Banner.joins(: banner_types) ActiveRecord:: ConfigurationError: Ассоциация с именем "banner_types" не найдена; возможно, вы его опечалили?
В .joins(:banner_type)
, :banner_type
- это отношение, к которому вы присоединяетесь, а не таблица. У вас
has_one :banner_type
так что Rails объединяется. Это как раз то, как Rails работает, когда вы передаете символ в .joins
, и поэтому ошибка относится к ассоциации при передаче символа, не соответствующего какой-либо существующей ассоциации для вашей модели.
Вот почему вы можете сделать JOIN
несколько уровней с использованием символов для вложенных ассоциаций, как описано в Rails Guide
Category.joins(:posts => [{:comments => :guest}, :tags])
Также описывается в Rails Guide, вы также можете передать Strings на .joins
.
Client.joins('LEFT OUTER JOIN addresses ON addresses.client_id = clients.id')
Примечание в этом последнем примере, когда String передается в joins
, используется имя таблицы addresses
, а не имя ассоциации; это помогает ответить # 3.
# 3
Почему для предложения where нужны banner_types, а не banner_type (т.е. плюрализуемая версия - то есть имя таблицы, а не символ, используемый в методе соединений)? Кажется, было бы более интуитивно, если бы вы использовали имена таблиц в обоих местах или используйте имена символов в обоих местах. Если, по крайней мере, для целей последовательности.
После немного интерполяции строк строки, переданные методу where
(похожие на joins
), более или менее передаются непосредственно в конечный SQL-запрос (с помощью ARel будет немного манипулировать), name
- неоднозначный столбец (обе таблицы banners
и banner_types
имеют столбец name
), поэтому, ссылаясь на таблицу, требуется полный путь [TABLE NAME].[COLUMN NAME]
. Если, например, у вас был столбец color
в banner_types
(который также не существовал в banners
), нет необходимости использовать его как "banner_types.color = ?"
в вашем методе where
; "color = ?"
будет работать нормально.
Примечание. Как и в # 2, вы можете передавать символы в метод where
для таблиц JOIN
'd.
Banner.joins(:banner_type).where(banner_type: [name: 'Featured'])
# 4
Почему я не могу выполнять динамическое обнаружение через ассоциации - то есть было бы хорошо, если бы я мог сделать Banner.find_by_banner_type_name ( "Featured" )?
Вы не можете так найти, потому что он не поддерживается в AREL, это так просто (IMO, имя метода, как find_by_banner_type_name
, довольно запутывающее).