Rails Active Storage上传偶现失败 record_id为nil问题排查求助
排查建议
优先修复模型类拼写错误
你的模型定义里父类写错了,Rails 中默认的模型父类是单数的ApplicationRecord,你写的是复数ApplicationRecords,会导致偶发的模型加载异常、实例属性丢失,先修改为正确写法:class TournamentMatch < ApplicationRecord has_many_attached :score_cards end校验TournamentMatch实例是否存在
你在控制器中使用find_by(id: tournament_match_id)查询记录,该方法在找不到对应记录时会返回nil,你的代码没有做空值判断。如果tournament_match为nil,调用score_cards.attach本应抛出NoMethodError,如果你的应用配置了全局异常捕获,会导致异常被吞,逻辑误判为执行成功,同时关联创建时record_id自然为nil。
可以在attach执行前增加日志校验:Rails.logger.info "查询到的TournamentMatch实例:#{tournament_match&.inspect}, 传入的ID:#{tournament_match_id}"复现失败场景后查看日志,确认是否出现实例为nil的情况。
检查session有效性
你通过session传递tournament_match_id,偶发失败大概率是session丢失导致:- 检查是否用户在上传页停留过久触发session过期
- 检查你的session存储配置是否异常,比如cookie存储场景下用户清除了cookie、跨域请求未携带cookie
- 在create动作开头打印session取值日志,确认
session[:tournament_match_id]是否正常获取
确认attach返回值逻辑
Active Storage的attach方法默认只有在附件校验失败时才会返回false,你当前未配置任何附件校验规则,只要关联实例存在默认永远返回true。
控制台执行返回false时,可以直接调用tournament_match.errors.full_messages查看具体错误原因,和控制器执行场景做对比。检查Active Storage表结构
你提到失败时record_id为0,大概率是你修改了Active Storage默认的active_storage_attachments表结构:- 检查是否给
record_id字段设置了默认值0 - 检查是否删除了
record_id的非空约束,导致nil被转为0存入数据库
可以执行rails db:migrate:status检查Active Storage相关的迁移是否被修改。
- 检查是否给
内容的提问来源于stack exchange,提问作者r3b00t

