Rails 3.0.3 Rails.cache.read无法写入DB

时间:2011-04-12 03:48:53

标签: ruby-on-rails activerecord

我正在使用Rails 3 Rails.cache功能,当我将ActiveRecord条目写入缓存时,我无法读回,更改属性然后写入数据库。我得到一个" TypeError:无法修改冻结哈希"。我曾经使用过另一个memcache插件,但是我试图切换到Heroku,而且我无法保存我扔进Memcache的ActiveRecord条目,令人难以置信的烦恼。这将导致大量不必要的DB读取,以改变一小部分信息。

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

用户 - > 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='

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

2 个答案:

答案 0 :(得分:1)

从此行获取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

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

答案 1 :(得分:0)

将对象存储在缓存中时,该对象将被冻结。这是您永远不应存储复杂对象的原因之一,例如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'