Ruby on Rails: 对ActiveRecord 的引用是一个快照?

Ruby on Rails: reference to ActiveRecord is a snapshot?

假设我有一个 class User 继承自 ActiveRecord::Base,它有一个 :name 属性。然后在控制台中我通过以下方式创建一个新用户:

> user1 = User.create(name: 'Bob')
=> #<User id: 1, name: 'Bob'>

然后我将用户名更新为'Bob'。注意我没有做 user1.update_attribute.

> User.find_by(name: 'Bob').update_attribute(:name, 'Bill')

现在输入:

> User.find_by(name: 'Bob')
=> nil
> User.find_by(name: 'Bill')
=> #<User id: 1, name: 'Bill'>

这是我所期望的。但是,当我检查 user1 参考资料时,我得到:

> user1
=> #<User id: 1, name: 'Bob'>

不知何故,这仍然是旧用户名。 user1 不是对 ActiveRecord 的引用吗?它是某种快照吗?

那是它还留在记忆中的东西。 user1.reload 将创建新的 select 和 return 刷新记录。

您的 user1 没有自动更新。您需要先致电user1.reload

ActiveRecord 从数据库中获取数据并将其转换为对象。所以是的,它实际上是一个快照。没有好的方法可以确定它的任何值是否在此期间发生了变化。虽然某些数据库引擎提供某种 listen/notify,但对每个对象执行此操作是主要的(并且大部分时间无用)性能开销。

有其他 ORM 遵循 "the same row is the same object" 原则(例如 DataMapper,参见 "Identity map"),但在某些情况下也不可靠:在此期间,对象可能已被您的 ORM 不知道的不同进程修改。

因此 ActiveRecord 提供了 折衷方案 :它缓存对象,但留给您 reload 方法,该方法使用数据库中的数据刷新对象 就地返回自身,这样你就可以获取它并对其进行操作而无需额外的分配。