I am trying to cache results of Active Record Query.
Here is my use case:
User.rb
def self.awesome_users_cached
Rails.cache.fetch("awesome_users") { where(awesome: true) }
end
UsersController
def index
all_awesome_users = User.awesome_users_cached
less_awesome_users = User.where(less_awesome_user:true).pluck(:id)
@users = all_awesome_users.where.not(id: less_awesome_users)
end
Here are 2 issues:
- self.awesome_users_cached doesnt cache the results and ends up hitting the
- all_awesome_users ends up as an array instead of active Record and hence I cannot filter out less_awesome_users from it.
There was a solution that doesnt seem to work in Rails4 anymore: Rails cache with where clause
You should never cache ActiveRecord instances, or complex objects in general. Rather, you should cache simple primitive values, such as the primary keys of the records.
In your case, there is one more issue.
where(awesome: true)
is returning a scope, not a query result. Because the scope is lazy-executed, you effectively never cache anything but the query is always executed.If you want to cache the lookup, execute the heavy query and return the IDs of the affected records. Then perform a second query fetching the records by id. You will be running 2 queries, but the first one (the most expensive one) will be cached after the first time.
You can cache the lookup of the first query, but as I mentioned before it is not a good idea.
You can also use a different query approach so that you can easily chain additional conditions to the cached query.