Rails中after_save回调里记录已持久化却无法找到的问题
问题分析:after_save回调中记录的状态解析
核心结论
这条BinSet记录当前处于内存中已实例化、对象自身标记为已持久化,但数据库事务未提交,外部查询无法读取的状态。
关键原因拆解
Rails回调与事务的执行顺序
Rails默认情况下,after_save回调是在数据库事务未提交时触发的——save方法执行完成仅意味着对象的变更已写入事务缓冲区,而非真正提交到数据库。此时:- 对象的
id会被提前分配(数据库自增ID在事务内就会生成) persisted?返回true(这是Rails对象内部的状态标记,仅表示对象有ID且不是新建状态,不代表数据库已完成持久化)- 直接通过
BinSet.find或reload查询数据库会失败,因为事务未提交时,外部查询无法读取未提交的事务内容。
- 对象的
重复调用
save!无效的原因
在after_save回调内再次执行self.save!,只会重新触发模型的验证和回调逻辑,但不会提交当前的事务。因此即使save!返回true,数据库里依然不会有这条记录的最终数据。ActiveStorage附件的异常关联
self.bins_table.attached?返回true:这只是内存中标记附件已关联,并非数据库中已存在关联记录download触发FileNotFoundError:ActiveStorage的附件关联操作和主记录处于同一个事务,事务未提交时,附件的关联数据或实际文件还未完成持久化,导致无法读取。
断点期间执行的命令输出佐证
0> self.inspect => #<BinSet id: 1131, name: "test upload", ...> 0> self.bins_table.download => Error: the evaluation of `self.bins_table.download` failed with the exception 'ActiveStorage::FileNotFoundError' 0> self.bins_table.attached? => true 0> self.reload => Error: the evaluation of `self.reload` failed with the exception 'Couldn't find BinSet with 'id'=1131' 0> self.id => 1131 0> self.persisted? => true 0> BinSet.find(1131) => Error: the evaluation of `BinSet.find(1131)` failed with the exception 'Couldn't find BinSet with 'id'=1131' 0> self.save! => true 0> self.id => 1131 0> BinSet.find(1131) => Error: the evaluation of `BinSet.find(1131)` failed with the exception 'Couldn't find BinSet with 'id'=1131'
内容的提问来源于stack exchange,提问作者Jacob Miller
相关产品推荐
相关产品推荐

