Все, что я читаю, советует людям не допускать «сложных» запросов к контроллеру и помещать их в области видимости модели. Однако как вы порекомендуете сделать это с запросом, которому нужны данные из трех моделей при использовании joins
. Например,
class User < ActiveRecord::Base
belongs_to :company
belongs_to :profile
end
Если нам нужны companies.name
и profiles.city
из User
, мы могли бы вставить запрос в действие контроллера, что отлично работает.
User.joins(:company, :profile).select('users.*, companies.name as company_name, profiles.city as city').find(1)
Чтобы не допустить этого в контроллере, мы могли бы определить именованную область видимости, например
scope :include_company_name_and_profile_city, -> { joins(:company, :profile).select('users.*, companies.name as company_name, profiles.city as city') }
а в контроллере используйте User.include_company_name_and_profile_city.find(1)
.
Но что, если в разное время нам нужно только название компании или только город профиля? Можем ли мы определить две области и связать их?
scope :include_company_name, -> { joins(:company).select('users.*, companies.name as company_name') }
scope :include_profile_city, -> { joins(:profile).select('users.*, profiles.city as city') }
Вызов User.include_company_name.include_profile_city.find(1)
даст запрос, который включает два users.*
в предложении SELECT.
SELECT users.*, companies.name as company_name, profiles.city as city, users.*, ...
Каков рекомендуемый способ справиться с этим?
- Поместить все вызовы
joins()
иselect()
в контроллер? - Создать одну область, которая загружает общие данные ассоциации и не заботится о возможных накладных расходах, если эти данные никогда не используются? (это ошибочно, см. ниже)
- Создать несколько именованных областей, не содержащих
select('users.*')
, и добавитьselect('users.*')
либо в контроллере, либо в области по умолчанию? - Имеет ли значение наличие нескольких
users.*
в предложении select?
Если люди рекомендуют вариант 2, как насчет ситуации, когда нам нужно больше (не очень распространенных) данных ассоциации в каком-то другом шаблоне? (т.е. User.include_common_association_data.include_non_common_association_data.find(1)
). Это будет иметь ту же проблему, о которой говорилось выше (несколько users.*
в предложении select).