Rails Active Record:attribute_before_last_save与attribute_was的差异疑问
为啥
attribute_before_last_save 和 attribute_was 表现不一样? 我之前踩过这个坑!这俩方法看着文档描述相似,但实际触发逻辑和依赖的状态完全是两回事,给你掰扯清楚:
核心差异:跟踪的是不同阶段的旧值
attribute_was(比如name_was):它盯的是当前对象内存里的未保存变更。- 如果你刚从数据库加载对象,没做任何修改,它会返回和当前属性一样的值(因为没有变更);
- 一旦你修改了属性但还没
save,它就会牢牢记住修改前的那个值; - 等你
save之后,Rails会把这个值重置成当前的数据库值,因为内存里的变更已经落地了。
举个代码例子:
# 创建并保存初始对象 user = User.create(name: "Alice") user.name_was # => "Alice"(无变更,和当前值一致) # 修改但未保存 user.name = "Bob" user.name_was # => "Alice"(记住修改前的值) # 保存后 user.save user.name_was # => "Bob"(重置为当前数据库值)attribute_before_last_save:它盯的是最后一次成功保存到数据库之前的旧值,而且只有当对象经历过「修改→保存」的完整流程后才会有值:- 新创建的对象刚
save完,调用它会返回nil(因为还没有第二次保存); - 当你修改属性并
save之后,它会返回这次save之前的那个旧值; - 如果你重新加载对象(
user.reload),它会变回nil,因为reload后没有新的保存操作触发它记录值。
对应代码例子:
# 创建并保存初始对象 user = User.create(name: "Alice") user.attribute_before_last_save(:name) # => nil(无二次保存) # 修改并保存 user.name = "Bob" user.save user.attribute_before_last_save(:name) # => "Alice"(返回最后一次保存前的值) # 重新加载对象 user.reload user.attribute_before_last_save(:name) # => nil(reload后重置)- 新创建的对象刚
你遇到的场景大概率是这样
你说一个返回nil、一个返回正确值,常见的两种情况:
- 你刚从数据库加载了对象,没做任何修改:这时候
attribute_was返回当前值(正确),而attribute_before_last_save因为没有经历过「修改→保存」的二次流程,返回nil; - 你修改了属性但还没
save:这时候attribute_was能拿到修改前的值,但attribute_before_last_save因为还没触发新的保存,所以返回nil。
怎么选?
- 要当前内存中未提交的修改前的值:用
attribute_was(或动态生成的xxx_was方法); - 要最后一次落地到数据库之前的旧值:用
attribute_before_last_save,但记得确保对象已经完成至少一次「修改→保存」的操作,不然会拿到nil。
内容的提问来源于stack exchange,提问作者Abhinav Srivastava
相关产品推荐
相关产品推荐

