Confusion caching Active Record queries with Rails.cache.fetch

caching, ruby-on-rails

Solution

The reason is because

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

returns an `ActiveRecord::Relation` which is actually a scope, not a query. Rails caches the scope.

If you want to cache the query, you need to use a query method at the end, such as `#all`.

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

Please note that it's never a good idea to cache ActiveRecord objects. Caching an object may result in inconsistent states and values. You should always cache primitive objects, when applicable. In this case, consider to cache the ids.

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

You may argue that in this case a call to `User.find` it's always executed. It's true, but the query using primary key is fast and you get around the problem I described before. Moreover, caching active record objects can be expensive and you might quickly end up filling all Memcached memory with just one single cache entry. Caching ids will prevent this problem as well.

Problem

My version is: - Rails: 3.2.6 - dalli: 2.1.0 My env is: - config.action_controller.perform_caching = true - config.cache_store = :dalli_store, 'localhost:11211', {:namespace => 'MyNameSpace'} When I write: ``` Rails.cache.fetch(key) do User.where('status = 1').limit(1000) end ``` The user model can't be cached. If I use ``` Rails.cache.fetch(key) do User.all end ``` it can be cached. How to cache query result?

Original source