Это должно работать для вас:
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
и позволить rails
и arel
обрабатывать все остальное, как
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
Это покажет всех людей, совершивших платежи в заданном диапазоне дат (вместе с этими платежами), отсортированных по сумме этих платежей по убываниюorder.
Это не проверено, так как я не удосужился настроить целое приложение rails, но оно должно быть функциональным.