为什么自定义created_before Scope会匹配创建时间等于参数的记录?
问题根源分析
- 参数绑定错误:你定义的Scope中存在错误的字符串插值操作,
where("created_at < ?","#{before_date}")写法会先将before_date时间对象转为字符串,再传入SQL占位符,而非直接传递时间对象保留完整精度。正确写法应为where("created_at < ?", before_date),无需额外添加引号和插值逻辑。 - 时间精度丢失:Ruby的Time对象默认字符串输出仅精确到秒,而数据库中
created_at字段通常会存储毫秒、微秒级的精度。你在控制台看到的Fri, 09 Jul 2021 21:44:05 UTC +00:00是截断了小数秒的展示值,实际数据库存储的该记录时间可能为2021-07-09 21:44:05.xxx。当你把时间转成秒级字符串传入SQL时,数据库会判定2021-07-09 21:44:05.xxx > '2021-07-09 21:44:05',因此同一条记录会被包含在查询结果中。
你可以通过以下代码查看时间的完整精度验证该问题:
p.created_at.strftime("%Y-%m-%d %H:%M:%S.%6N")
修复方案
# 修复精度丢失问题的Scope,直接传递时间对象 scope :created_before, ->(before_date) { where("created_at < ?", before_date) } # 若存在多条记录created_at完全一致的场景,推荐联合ID做分批条件,避免重复/漏数据,和你改用ID的方案逻辑一致 scope :paginate_by_time_and_id, ->(last_created_at, last_id) { where("created_at < ? OR (created_at = ? AND id < ?)", last_created_at, last_created_at, last_id) .order(created_at: :desc, id: :desc) }
内容的提问来源于stack exchange,提问作者Tristin
相关产品推荐
相关产品推荐

