[我正在尝试创建一个范围,为我提供在他们获得clients
之后就创建了purchase
的所有:transitioned_to_maintenance
(我们在内部使用的术语)。
我的模型和范围的组织方式如下:
class Client < ApplicationRecord
has_many :program_transitions
has_many :purchases
scope :transitioned_to_maintenance, -> { where(id: ProgramTransition.to_maintenance.pluck(:client_id)) }
scope :has_purchases, -> { where(id: Purchase.pluck(:client_id)) }
end
class ProgramTransition < ApplicationRecord
belongs_to :client, required: true
scope :to_fm, -> { where(new_status: "full maintenance") }
scope :to_lm, -> { where(new_status: "limited maintenance") }
scope :to_maintenance, -> { to_fm.or(to_lm)}
end
class Purchase < ActiveRecord::Base
belongs_to :client
end
我可以通过遍历客户端并选择满足我的条件的客户端来完成我想做的事情,但是我希望可以通过一个范围来实现。这是模型级别的函数:
def self.purchased_after_maintenance
clients = Client.transitioned_to_maintenance.has_purchases
final = []
clients.each do |client|
min_date = client.program_transitions.to_maintenance.first.created_at
final << client if client.purchases.last.created_at >= ? min_date
end
end
这是否可以与作用域一起使用,而无需遍历所有客户端?
解决主要问题之前的几件事。并不是要烦人,不要先解决主要问题,但我认为这可能会有所帮助。
scope :transitioned_to_maintenance, -> { where(id: ProgramTransition.to_maintenance.pluck(:client_id)) }
,我会这样做(请参见下文)。 merge非常强大,最近我们在公司中使用了很多东西。scope :transitioned_to_maintenance, -> { joins(:program_transitions).merge(ProgramTransition.to_maintenance) }
scope :has_purchases, -> { where(id: Purchase.pluck(:client_id)) }
,而是执行scope :has_purchases, -> { joins(:purchases) }
,因为购买的联接只会返回具有关联购买的客户。 关于主要问题,我想不出使用范围来实现此目标的好方法,但可能是可行的。如果您是我,我会问您的数据团队该查询的SQL外观如何,然后尝试找出创建该查询所需的活动记录。但是,如果您坚持使用自己的方法,我建议您稍作调整。使用select
而不是each
并渴望加载以避免n + 1个查询。
def self.purchased_after_maintenance
Client.joins(:purchases, :program_transitions).includes(:purchases, :program_transitions).transitioned_to_maintenance.select do |client|
transition_date = client.program_transitions.to_maintenance.first.created_at
client.purchases.last.created_at >= transition_date
end
end
希望这会有所帮助,很抱歉,我对范围没有答案。