Rails中Chartkick按日期累计图表无法正确显示数值下降问题
Rails + Chartkick 累计活跃错误图表实现方案
问题根因
现有实现逻辑存在两个核心缺陷,导致图表数值只涨不跌:
- 统计时直接过滤掉了所有当前状态为
resolved的错误,历史上被标记为解决的错误完全没有进入统计基数,相当于这些错误从来没存在过,自然无法体现“错误被解决导致存量下降”的逻辑 - 数据模型缺失错误解决时间字段,无法定位错误从活跃变为已解决的时间节点,根本没法按时间维度统计每日减少的错误量
修复步骤
1. 补全数据模型字段
首先给errors表添加resolved_at时间字段,用于记录错误被标记为解决的具体时间:
# 执行数据库迁移 class AddResolvedAtToErrors < ActiveRecord::Migration[7.0] def change add_column :errors, :resolved_at, :datetime end end
同步修改错误状态更新的业务逻辑:
- 错误状态从
active变更为resolved时,给resolved_at字段赋值为当前时间 - 如果存在状态回滚(已解决错误重新打开变为活跃),将
resolved_at字段置为nil - 历史已存在的
resolved状态数据,可根据业务内的操作日志回填resolved_at值,无日志的可暂时用状态最后更新时间填充
2. 调整统计逻辑
每日活跃错误存量的计算逻辑遵循公式:当日活跃存量 = 前一日活跃存量 + 当日新增首次出现的错误数 - 当日被解决的错误数
对应实现代码:
# 定义统计时间范围 start_date = 30.days.ago.to_date end_date = Time.zone.today # 统计时间范围起始点之前的历史活跃错误存量 base_total = Error.where("first_occurrence_date < ?", start_date) .where(resolved_at: nil) .count # 按天统计统计周期内每日首次出现的新增错误数 daily_new = Error.where(first_occurrence_date: start_date..end_date) .group_by_day(:first_occurrence_date, range: start_date..end_date) .count # 按天统计统计周期内每日被解决的错误数 daily_resolved = Error.where.not(resolved_at: nil) .where(resolved_at: start_date..end_date) .group_by_day(:resolved_at, range: start_date..end_date) .count # 递推计算每日活跃错误存量 daily_active = (start_date..end_date).each_with_object({}) do |date, result| base_total += daily_new[date].to_i - daily_resolved[date].to_i result[date] = base_total end # 传入Chartkick生成图表 line_chart daily_active
逻辑验证
用提供的模拟场景代入计算,结果完全匹配预期:
- 周一:新增0,解决0,存量0 → 输出0
- 周二:新增10,解决0,存量0+10=10 → 输出10
- 周三:新增0,解决2,存量10-2=8 → 输出8
- 周四:新增4,解决0,存量8+4=12 → 输出12
- 周五:新增0,解决2,存量12-2=10 → 输出10
内容的提问来源于stack exchange,提问作者Grégory Prève
相关产品推荐
相关产品推荐

