Rails 附件功能异常:归档时生成的PDF无法持久化附着
遇到这种「debug时明明显示附件已附着,但方法结束后就消失」的问题,大概率是事务回滚或者回调时机不对导致的,结合你描述的老代码突然失效的情况,给你几个排查方向和解决方案:
1. 优先排查回调触发时机
你提到在store_physical_copy_on_freeze!方法里用byebug看到physical_copy.attached?为true,但方法结束后就没了——这很可能是因为这个方法在事务提交前执行了,之后整个事务因为某些原因回滚,导致附件的保存也被撤销了。
比如如果你的回调是这么定义的:
after_save :store_physical_copy_on_freeze!
改成after_commit试试,确保在事务彻底提交后再生成并附着PDF:
after_commit :store_physical_copy_on_freeze!, on: [:update]
(加上on: [:update]是因为归档应该是更新操作,避免创建时误触发)
2. 检查当前是否处于活跃事务中
在store_physical_copy_on_freeze!方法里加一行调试代码,看看执行时是否有未提交的事务:
def store_physical_copy_on_freeze! puts "当前活跃事务数:#{ActiveRecord::Base.connection.open_transactions}" # 原方法代码... end
如果输出大于0,说明当前在事务里,这时候附着的附件会和事务绑定,一旦事务回滚(比如后续有验证失败、异常抛出),附件也会被删除。
3. 确认附件验证和存储配置
虽然你说没改配置,但还是可以快速排查:
- 检查
OutInvoice模型里对physical_copy的验证规则,比如有没有限制content_type:
如果有的话,附着时明确指定content_type,避免自动识别出错:validates :physical_copy, content_type: { in: 'application/pdf' }physical_copy.attach( io: StringIO.new(pdf), filename: "#{pdf_name}.pdf", content_type: 'application/pdf' ) - 本地存储的话,检查
public/storage目录的读写权限,确保Rails进程能写入;如果是云存储,确认密钥、存储桶权限是否正常。
4. 手动控制台测试验证
在rails控制台里手动执行方法,验证持久化情况:
out_invoice = OutInvoice.find(你的测试ID) out_invoice.store_physical_copy_on_freeze! out_invoice.reload # 重新从数据库加载 out_invoice.physical_copy.attached? # 看看是否还是true
如果reload后变成false,基本可以确定是事务或回调时机的问题;如果还是true,那可能是前端渲染的问题,但你说控制台也看不到,所以大概率是前者。
5. 排查其他回调干扰
检查Invoice或OutInvoice模型有没有其他after_save/after_commit回调,有没有可能在你附着PDF后,其他方法又把它移除了?比如有没有类似reset_physical_copy之类的逻辑?
备注:内容来源于stack exchange,提问作者Julian

