【发布时间】:2013-12-03 17:04:57
【问题描述】:
我阅读的所有内容都建议人们将“复杂”查询排除在控制器之外,并将它们放入模型的范围内。但是,您如何建议在使用joins 时使用需要来自三个模型的数据的查询来执行此操作。例如,
class User < ActiveRecord::Base
belongs_to :company
belongs_to :profile
end
如果我们需要来自User 的companies.name 和profiles.city,我们可以将查询填充到控制器操作中,这非常有效。
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) 将产生一个在SELECT 子句中包含两个users.* 的查询。
SELECT users.*, companies.name as company_name, profiles.city as city, users.*, ...
推荐的处理方法是什么?
- 将所有
joins()和select()调用放入控制器中? - 创建一个加载公共关联数据的作用域,并且不关心如果该数据从未使用过可能产生的开销? (这是有缺陷的 imo,见下文)
- 创建多个不包含
select('users.*')的命名作用域并在控制器或默认作用域中附加select('users.*')? - 在 select 子句中有多个
users.*是否重要?
如果人们推荐选项 2,那么在其他模板中我们需要更多(不那么常见)关联数据的情况呢? (即User.include_common_association_data.include_non_common_association_data.find(1))。这将遇到上面提到的相同问题(在 select 子句中有多个 users.*)。
【问题讨论】:
标签: ruby-on-rails rails-activerecord