如何在ActiveRecord中订购累计付款?

时间:2018-12-14 14:29:43

标签: ruby-on-rails ruby activerecord

在我的Rails应用程序中,我具有以下模型:

class Person < ApplicationRecord

  has_many :payments

end

class Payment < ApplicationRecord

  belongs_to :person

end

如何获得每个payments的{​​{1}}并按 sum 排序?

这是我的控制者:

person

它给我正确的数字,但顺序错误。我希望它从class SalesController < ApplicationController def index @people = current_account.people.includes(:payments).where(:payments => { :date => @range }).order("payments.amount DESC") end end 内付款金额最高的person开始。

这是当前的range表:

enter image description here

这怎么办?

1 个答案:

答案 0 :(得分:2)

这应该为您工作:

payments = Payment.arel_table
sum_payments = Arel::Table.new('sum_payments')
payments_total = payments.join(
     payments.project(
       payments[:person_id],
       payments[:amount].sum.as('total')
     )
     .where(payments[:date].between(@range))
     .group( payments[:person_id])
     .as('sum_payments'))
     .on(sum_payments[:person_id].eq(Person.arel_table[:id]))

这将创建损坏的SQL(从语法上不正确的付款中选择任何内容,并连接到此查询中甚至不存在的人),但实际上我们只需要连接,例如

 payments_total.join_sources.first.to_sql
 #=> INNER JOIN (SELECT payments.person_id, 
 #     SUM(payments.amount) AS total 
 #      FROM payments 
 #      WHERE 
 #        payments.date BETWEEN ... AND ...
 #       GROUP BY payments.person_id) sum_payments 
 #      ON sum_payments.id = people.id

因此知道了这一点,我们就可以将join_sources传递给ActiveRecord::QueryMethods#joins并让railsarel像这样处理其余部分

current_account
 .people
 .includes(:payments)
 .joins(payments_total.join_sources) 
 .where(:payments => { :date => @range })
 .order("sum_payments.total DESC")

哪个应导致SQL类似于

SELECT 
 -- ...
FROM 
  people
  INNER JOIN payments ON payments.person_id = people.id 
  INNER JOIN ( SELECT payments.person_id,
                 SUM(payments.amount) as total
               FROM payments
               WHERE 
                  payments.date BETWEEN -- ... AND ...
               GROUP BY payments.person_id) sum_payments ON 
     sum_payments.person_id = people.id
WHERE
   payments.date BETWEEN -- ... AND ..
ORDER BY 
   sum_payments.total DESC

这将显示所有在给定日期范围内付款的人(以及这些付款),并按这些付款的总和降序排列。

这是未经测试的,因为我不必费心设置整个Rails应用程序,但它应该可以工作。