混淆使用Rails.cache.fetch缓存Active Record查询

时间:2012-06-27 03:17:38

标签: ruby-on-rails caching

我的版本是:

  • Rails:3.2.6
  • dalli:2.1.0

我的环境是:

  • config.action_controller.perform_caching = true
  • config.cache_store =:dalli_store,'localhost:11211',{:namespace => 'myNameSpace对象'}

当我写:

 Rails.cache.fetch(key) do
     User.where('status = 1').limit(1000)
 end

无法缓存用户模型。如果我使用

 Rails.cache.fetch(key) do
     User.all
 end

它可以被缓存。如何缓存查询结果?

4 个答案:

答案 0 :(得分:32)

原因是因为

User.where('status = 1').limit(1000)

返回ActiveRecord::Relation,它实际上是范围,而不是查询。 Rails缓存了范围。

如果要缓存查询,则需要在最后使用查询方法,例如#all

Rails.cache.fetch(key) do
  User.where('status = 1').limit(1000).all
end

请注意缓存ActiveRecord对象永远不是一个好主意。缓存对象可能会导致状态和值不一致。在适用的情况下,应始终缓存基本对象。在这种情况下,请考虑缓存ID。

ids = Rails.cache.fetch(key) do
  User.where('status = 1').limit(1000).pluck(:id)
end
User.find(ids)

您可能会争辩说,在这种情况下,对User.find的调用始终会执行。这是真的,但使用主键的查询速度很快,你可以解决我之前描述的问题。此外,缓存活动记录对象可能很昂贵,并且您可能很快就会用一个缓存条目填充所有Memcached内存。缓存ID也可以防止此问题。

答案 1 :(得分:3)

除了选定的答案:对于Rails 4+,您应该使用load代替all来获取范围的结果。

答案 2 :(得分:2)

Rails.cache.fetch正好缓存了块计算的内容。

 User.where('status = 1').limit(1000)

只是一个范围,所以缓存的只是ActiveRecord :: Relation对象,即查询,而不是其结果(因为查询尚未执行)。

如果你想要一些有用的东西被缓存,你需要强制执行块内的查询,例如通过

User.where('status = 1').limit(1000).all

请注意,在导轨4上,all不会强制加载关系 - 请改用<{1}}

答案 3 :(得分:0)

使用

User.where("status = 1").limit(1000).all

应该有用。