使用select()的Rails ActiveRecord / Arel查询聚合列

时间:2016-10-29 17:44:11

标签: ruby-on-rails arel

我有两个带连接表的基本模型。我已经添加了一个范围来计算关系中的计数,并将其作为属性/ psuedo-column公开。一切正常,但我现在想查询列的子集并包含计数列,但我不知道如何引用它。

tldr;如何在我的Arel查询中包含聚合(如计数),同时还要选择列的子集?

模型为EmployerEmployee,通过Job加入。这是Employer的相关代码:

class Employer < ApplicationRecord
  belongs_to :user
  has_many :jobs
  has_many :employees, through: :jobs

  scope :include_counts, -> do
    left_outer_joins(:employees).
      group("employers.id").
      select("employers.*, count(employees.*) as employees_count")
  end
end

这允许我向雇主加载计数:

employers = Employer.include_counts.where(id: 1)

然后引用计数:

count = employers[0].employees_count

我在我的控制器中加载记录,然后呈现它。但是,我不想渲染超出我需要的字段。在添加计数之前,我可以这样做:

employers = Employer.where(id: 1).select(:id, :name)

当我添加include_counts范围时,它基本上忽略了select()。它并没有失败,但最终包括所有列,因为我的范围内有这一行:

select("employers.*, count(employees.*) as employees_count")

如果我从范围中移除employers.*,那么无论是否有select()条款,我都不会在结果中获得任何列。

我试过了:

employers = Employer.include_counts.where(id: 1).select(:id, :name, :employee_counts)

...但是会产生以下SQL:

SELECT employers.*, count(employees.*) as employees_count, id, name, employees_count FROM

...和SQL错误,因为列employees_count不存在且idname不明确。

唯一有用的是:

employers = Employer.include_counts.where(id: 1).select("employers.id, employers.name, count(employees.*) as employees_count")

...但实际上选择employers中的所有列,由于scope子句再次出现。

如果可以避免,我也不希望原始SQL泄漏到我的控制器中。使用Rails / Arel是否有更惯用的方法?

如果我找不到另一种方法来进行查询,我可能会在模型中创建另一个范围或自定义查找程序,以便控制器代码更清晰。我也愿意接受这样做的建议,但是我想知道是否有一种简单的方法来引用像这样的计算聚合列,就好像它们是任何其他列一样。

0 个答案:

没有答案