You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何改进Category模型的Scope以返回含交易总额的自定义数据?

改进Category Scope以包含交易总额

嘿,我来帮你调整这个scope,让它既能按交易总额排序,又能把总额作为属性返回给每个Category实例。

首先,你可以通过select方法把计算出的总额作为别名字段选出来,同时把这段逻辑封装成可复用的scope会更方便。直接修改后的scope代码如下:

# 在Category模型中定义这个scope
scope :with_total_debit_amount, ->(time_range = 1.month.ago) {
  joins(:transactions)
    .where('transactions.created_at >= ?', time_range)
    .group('categories.id')
    .select('categories.*, SUM(transactions.debit_amount_cents) AS all_amount')
    .order('all_amount DESC')
}

为什么这么改?

  • select('categories.*, SUM(...) AS all_amount') 会把分类的所有字段,加上计算出的交易debit总额(别名为all_amount)一起查询出来,这样每个Category对象就会自带all_amount属性,你直接调用就行。
  • 我把时间范围做成了可选参数,默认是1个月前,这样你调用的时候可以灵活调整,比如想查3个月内的就用Category.with_total_debit_amount(3.months.ago)。

使用方式

调用这个scope后,就能直接访问每个分类的总额了:

@categories = Category.with_total_debit_amount

# 遍历输出示例
@categories.each do |cat|
  puts "id: #{cat.id}, name: #{cat.name}, all_amount: #{cat.all_amount}"
end

额外补充:保留无交易的分类

如果某个分类在指定时间范围内没有交易,上面的内连接(joins)会自动排除它。要是你想保留这些分类,并且让它们的all_amount显示为0,可以改成左外连接,同时用COALESCE处理NULL值:

scope :with_total_debit_amount, ->(time_range = 1.month.ago) {
  left_outer_joins(:transactions)
    .where('transactions.created_at >= ? OR transactions.id IS NULL', time_range)
    .group('categories.id')
    .select('categories.*, SUM(COALESCE(transactions.debit_amount_cents, 0)) AS all_amount')
    .order('all_amount DESC')
}

这里的left_outer_joins会保留所有分类,COALESCE把没有交易时的NULL总额转换成0,where条件里的transactions.id IS NULL确保无交易的分类不会被时间条件过滤掉。

内容的提问来源于stack exchange,提问作者SsPay

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 21:42:49