Как заказать накопительные платежи в ActiveRecord? - PullRequest
0 голосов
/ 14 декабря 2018

В моем приложении Rails у меня есть следующие модели:

class Person < ApplicationRecord

  has_many :payments

end

class Payment < ApplicationRecord

  belongs_to :person

end

Как мне получить payments для каждого person и заказать их по sum ?

Это мой контроллер:

class SalesController < ApplicationController

  def index
    @people = current_account.people.includes(:payments).where(:payments => { :date => @range }).order("payments.amount DESC")
  end

end

Это дает мне правильные цифры, но порядок неправильный.Я хочу, чтобы это началось с person с самой высокой суммой платежей в пределах range.

Это текущая таблица Payments:

enter image description here

Как это можно сделать?

1 Ответ

0 голосов
/ 14 декабря 2018

Это должно работать для вас:

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, но оно должно быть функциональным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...