混乱使用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
应该管用。