Rails 5.1多币种场景下支出金额分组求和实现方案
解决方案:按币种动态统计用户支出总额
这是个很常见的扩展性需求,要实现新增币种无需修改代码的灵活统计,最佳方式是利用数据库层面的分组查询,让ActiveRecord帮我们完成聚合统计,而不是在Ruby代码里做循环判断或遍历。
步骤1:优化控制器中的统计逻辑
修改UsersController#show方法,通过joins关联币种表,再用group和sum按币种分组统计总额,同时预加载币种信息避免N+1查询问题:
class UsersController < ApplicationController def show @user_spendings = @current_user.spendings.order(date: :desc).paginate(page: params[:page], per_page: 10) # 按币种分组统计,同时获取币种符号和总额 @currency_totals = @current_user.spendings.joins(:currency) .select('currencies.id, currencies.symb, SUM(spendings.amount) AS total_amount') .group('currencies.id, currencies.symb') end end
这个查询会返回一个ActiveRecord关系对象,每个对象包含币种的id、symb(符号)和total_amount(该币种的支出总额),而且不管新增多少种币种,这个查询都会自动包含它们,完全不需要修改代码。
步骤2:在视图中展示统计结果
在show.html.erb中添加统计区域,比如放在支出列表的上方或下方:
<!-- 按币种统计区域 --> <h3>支出总额(按币种)</h3> <table class="table"> <thead> <tr> <th>币种</th> <th>总金额</th> </tr> </thead> <tbody> <% @currency_totals.each do |total| %> <tr> <td><%= total.symb %></td> <td><%= '%.02f' % total.total_amount %></td> </tr> <% end %> </tbody> </table> <!-- 原支出列表 --> <h3>我的支出记录</h3> <table class="table"> <thead> <tr> <th>名称</th> <th>描述</th> <th>金额</th> <th>币种</th> <th>日期</th> </tr> </thead> <tbody> <% @user_spendings.each do |spending| %> <tr> <td><%= spending.title %></td> <td><%= spending.description %></td> <td><%= '%.02f' % spending.amount %></td> <td><%= spending.currency.symb %></td> <td><%= spending.date.strftime('%d %B %Y') %></td> </tr> <% end %> </tbody> </table>
为什么这个方案更优?
- 灵活性拉满:新增币种时,只要在
currencies表中添加新记录,统计逻辑会自动识别并计算该币种的总额,无需修改任何代码。 - 性能更好:统计逻辑在数据库层面完成,比把所有支出加载到Ruby中循环求和效率高得多,尤其是当用户支出记录较多时。
- 避免N+1查询:通过
joins关联币种表,一次性获取所有需要的币种信息,不会在遍历统计结果时触发额外的数据库查询。
备选方案(Ruby层面分组,不推荐大数据量)
如果你的用户支出数据量很小,也可以用Ruby的group_by方法在内存中分组统计,但性能不如数据库查询:
# 控制器中 @spendings_by_currency = @current_user.spendings.includes(:currency).group_by(&:currency) # 视图中 <% @spendings_by_currency.each do |currency, spendings| %> <p><%= currency.symb %>: <%= '%.02f' % spendings.sum(&:amount) %></p> <% end %>
这个方案虽然简单,但当支出记录上万条时,内存占用和计算速度都会明显下降,所以更推荐前面的数据库分组方案。
内容的提问来源于stack exchange,提问作者Asso
相关产品推荐
相关产品推荐

