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

我的版本是:

  • Rails:3.2.6
  • 达利: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 

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

原因是因为

 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也可以防止此问题。

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

Rails.cache.fetch准确缓存块计算的内容。

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

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

如果您希望缓存一些有用的东西,则需要在块内强制执行查询,例如通过执行

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

请注意,在rails 4上, all都不强制加载关系 – 请改用to_a

运用

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

应该管用。