如何从我的Rails关联中删除N + 1个查询?

Tin*_*n81 2 ruby activerecord ruby-on-rails

在我的Rails应用程序中,我有以下关联:

class Person < ApplicationRecord

  has_many :payments

  def sales_volume(range)
    payments.in_range(range).sum(&:amount)
  end

  ...

end
Run Code Online (Sandbox Code Playgroud)
class Payment < ApplicationRecord

  belongs_to :person

  def self.in_range(range)
    select { |x| range.cover?(x.date) }
  end

  ...

end
Run Code Online (Sandbox Code Playgroud)

在我的控制器中,我正在......

@people = Person.all.sort_by { |p| p.sales_volume(@range) }
Run Code Online (Sandbox Code Playgroud)

......它有效.

不幸的是,它产生了很多N + 1个查询.

有没有办法显示每个销售量person而不为每个人生成单独的SQL查询?


加成:

我已经尝试过急切加载......

@people = Person.all.includes(:payments).sort_by { |p| p.sales_volume(@range) }
Run Code Online (Sandbox Code Playgroud)

......但那也没有用.查询数量仍然相同.

Urs*_*sus 5

首先,让我们重写一下这个in_range方法ActiveRecord

def self.in_range(range)
  where(date: range)
end
Run Code Online (Sandbox Code Playgroud)

现在,那sales_volume.让我们说吧

def self.with_sales_volume(range)
  joins("LEFT JOIN payments ON payments.user_id = users.id").
    merge(Payment.in_range(range)).
    group('users.id').
    select('users.*, SUM(payments.amount) AS sales_volume')
end
Run Code Online (Sandbox Code Playgroud)

最后

@people = Person.from(Person.with_sales_volume(@range), :t).order('t.sales_volume DESC')
Run Code Online (Sandbox Code Playgroud)

这是个主意.我已经这么做了很多次,但是如果没有尝试并拥有所有信息,那真的很难.我想你可以解决它以防万一.如果你使用的是rails 5,你可以使用left_joins