Rails 3.0.3 Rails.cache.read 无法写入数据库

发布于 2024-10-31 20:22:42 字数 1007 浏览 1 评论 0原文

我正在使用 Rails 3 Rails.cache 功能,当我将 ActiveRecord 条目写入缓存时,我无法读回它、更改属性然后写入数据库。我收到“TypeError:无法修改冻结哈希”。我曾经使用另一个 memcache 插件,但我正在尝试切换到 Heroku,而且我无法保存放入 Memcache 中的 ActiveRecord 条目,这非常烦人。这将导致大量不必要的数据库读取来更改少量信息。

例如,我可能会在数据库中执行此操作。假设User模型为:

User -> login:string 并将以下内容输入到 Rails c

user = User.new
user.login = 'test'
user.save
Rails.cache.write('user:login:test', user)
user2 = Rails.cache.read('user:login:test')
user2.login = 'test2'
TypeError: can't modify frozen hash
/app/.bundle/gems/ruby/1.8/gems/activerecord-3.0.3/lib/active_record/attribute_methods/write.rb:26:in `[]='
    /app/.bundle/gems/ruby/1.8/gems/activerecord-3.0.3/lib/active_record/attribute_methods/write.rb:26:in `write_attribute'
    /app/.bundle/gems/ruby/1.8/gems/activerecord-3.0.3/lib/active_record/attribute_methods/dirty.rb:61:in `write_attribute'
    /app/.bundle/gems/ruby/1.8/gems/activerecord-3.0.3/lib/active_record/attribute_methods/write.rb:13:in `login='

有谁知道如何解决这个问题?

I am playing around with the Rails 3 Rails.cache feature and when I write an ActiveRecord entry to cache, I cannot read it back, change the attributes then write to the database. I get a "TypeError: can't modify frozen hash". I used to use another memcache plugin, but I'm trying to switch over to Heroku, and it's incredibly annoying that I cannot save ActiveRecord entries I throw into Memcache. This will result in a lot of unnecessary DB reads to change small bits of information.

For example, I might do this in the database. Assuming the User model is:

User -> login:string and typing the following into rails c

user = User.new
user.login = 'test'
user.save
Rails.cache.write('user:login:test', user)
user2 = Rails.cache.read('user:login:test')
user2.login = 'test2'
TypeError: can't modify frozen hash
/app/.bundle/gems/ruby/1.8/gems/activerecord-3.0.3/lib/active_record/attribute_methods/write.rb:26:in `[]='
    /app/.bundle/gems/ruby/1.8/gems/activerecord-3.0.3/lib/active_record/attribute_methods/write.rb:26:in `write_attribute'
    /app/.bundle/gems/ruby/1.8/gems/activerecord-3.0.3/lib/active_record/attribute_methods/dirty.rb:61:in `write_attribute'
    /app/.bundle/gems/ruby/1.8/gems/activerecord-3.0.3/lib/active_record/attribute_methods/write.rb:13:in `login='

Does anyone know how to solve this problem?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

乙白 2024-11-07 20:22:42

从这一行获取 user2 对象值后:

user2 = Rails.cache.read('user:login:test')

执行以下操作:

dup_user = user2.dup # this will make a clone of the user2 object
dup_user.login = test_2

然后“冻结哈希”异常不应再次出现。

After getting the user2 object value from this line:

user2 = Rails.cache.read('user:login:test')

do the following:

dup_user = user2.dup # this will make a clone of the user2 object
dup_user.login = test_2

Then the "frozen hash" exception should not appear again.

峩卟喜欢 2024-11-07 20:22:42

当您将对象存储在缓存中时,该对象将被冻结。这是您永远不应该存储复杂对象(例如 ActiveRecord 模型)的原因之一。

当您从缓存中读取时,对象会被加载,但它仍然处于冻结状态。 ActiveRecord 尝试恢复对象状态,但它需要更新一些内部属性。由于对象被冻结,更新将失败。

无需存储整个对象,只需存储其 id 并即时检索用户即可。

user = User.new
user.login = 'test'
user.save
Rails.cache.write('user:login:test', user.id)
user2 = User.find(Rails.cache.read('user:login:test'))
user2.login = 'test2'

这在缓存方面效率稍低,但这是可行的方法。事实上,您没有考虑到同时用户的其他属性可能已更改并且您的对象不再代表当前状态。

此外,通过这种方式,您的缓存存储将不会充当数据库,并且您将能够存储更多缓存条目。 ID 占用的内存比整个 ActiveRecord 实例占用的内存少。

当然,您可以使用#dup解决方法,但这只是一个技巧。这不是解决方案。正如我上面所解释的,您仍然会遇到缓存完整性问题。

user = User.new
user.login = 'test'
user.save
Rails.cache.write('user:login:test', user)
user2 = Rails.cache.read('user:login:test').dup
user2.login = 'test2'

When you store an object in cache, the object is frozen. This is one of the reasons why you should never store complex objects, like ActiveRecord models.

When you read from cache, the object is loaded, but it's still frozen. ActiveRecord tries to restore the object state, but it needs to update some internal attributes. The update will fail because the object is frozen.

Instead of storing the entire object, simply store its id and retrieve the user on-the-fly.

user = User.new
user.login = 'test'
user.save
Rails.cache.write('user:login:test', user.id)
user2 = User.find(Rails.cache.read('user:login:test'))
user2.login = 'test2'

This is a little bit less more efficient in terms of caching, but it's the way to go. In fact, you don't consider that in the meanwhile other attributes of the user might have been changed and your object no longer represents the current status.

Also, in this way your cache store won't act as a database and you'll be able to store more cache entries. IDs take less memory than an entire ActiveRecord instance.

Of course, you can use the #dup workaround, but it's just a trick. It's not the solution. You will still have problems with cache integrity as I explained above.

user = User.new
user.login = 'test'
user.save
Rails.cache.write('user:login:test', user)
user2 = Rails.cache.read('user:login:test').dup
user2.login = 'test2'
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文