按用户组计算付款的最有效方法

时间:2019-03-24 18:06:48

标签: ruby-on-rails memory activerecord eager-loading

在我的模特中,

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 个答案:

答案 0 :(得分:1)

通过反转联接表的方向,您只能加载与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