Самый эффективный способ расчета платежей по группам пользователей - PullRequest
0 голосов
/ 24 марта 2019

В моих моделях у меня есть

class Group < ApplicationRecord      
    has_many :payments, as: :paymentable   
    has_many :users
end

class User < ApplicationRecord  
  has_many   :payments, as: :paymentable   
  belongs_to :group    
end

class Payment < ApplicationRecord  
  belongs_to :paymentable, polymorphic: true
end

Я хотел бы рассчитать сумму общих пользовательских платежей по группе, поэтому в контроллере у меня есть это:

Group.includes(users: :payments).each do |group|  
  group.users.each do |user|
    user.payments.each do |payment|
         ............
         ...............
    end
  end
end

Изначально я думал, что Group.includes(users: :payments) - это хорошая идея, чтобы исключить эти n + 1 запросов. Однако это приводит к увеличению объема памяти, поскольку все пользователи и платежи загружаются в память.

Итак, я подумал о том, чтобы попытаться получить платежи отдельной группы, используя области для таких платежей, как этот

scope :for_paymentable_type,  -> (class_name) { where("for_paymentable_type= ?", class_name) }

scope :belongs_to_group, -> (group) { for_paymentable_type("User").includes(:paymentable).where("paymentable.group_id = ? ", group.id) }

но я не могу заставить его работать. Часть for_paymentable_type("User").includes(:paymentable) работает нормально, но where("paymentable.group_id = ? ", group.id) генерирует следующую ошибку:

ActiveRecord::StatementInvalid: SQLite3::SQLException: no such column: paymentable.tgroup_id: SELECT  "payments".* FROM "payments" WHERE (paymentable_type = 'User') AND (paymentable.group_id = 1 ) LIMIT ?

Есть идеи?

1 Ответ

1 голос
/ 24 марта 2019

Изменив направление объединения таблиц, вы можете загружать только пользователей и группы, связанные с Payment:

class Payment < ApplicationRecord  
  belongs_to :paymentable, polymorphic: true
  belongs_to :user, -> { where(payments: { paymentable_type: 'User' }) }, foreign_key: 'paymentable_id'
end

Payment.includes(user: :group).each do |payment|
  ...
end
...