I’m trying to list users on my homepage based on how many views their profile has. The users are paginated and I am trying to cache the users and invalidate that cache whenever a profile gets a new view.
My controller code:
def index
@users = Rails.cache.read(params[:page])
if !@users.nil?
flash[:info] = "Cache was hit."
else
flash[:info] = "Miss."
@users = User.paginate(page: params[:page], per_page: 5, order: "views DESC")
Rails.cache.write(params[:page], @users)
end
end
When I first go to page 2, I get a cache miss as expected, and when I refresh, I get a cache hit, also as expected. However, when I manually changed a user’s views via console and refreshed page 2, the change I made in console had affected the page, even though the page was supposed to have been rendered from the cache. The notice at the top still said “Cache was hit.”
Running Rails.cache.read("2") in console to pull up what my controller cached gave me this:
User Load (0.4ms) SELECT "users".* FROM "users" ORDER BY views DESC LIMIT 5 OFFSET 0
(0.2ms) SELECT COUNT(*) FROM "users"
=> users freshly pulled from the database
Manually caching the User.paginate value via console did not show the queries when Rails.cache.read was called:
test = User.paginate(page: 1, order: "views DESC")
=> users freshly pulled from the database
Rails.cache.write("9", test)
=> true
Rails.cache.read("9")
=> users from test; no queries displayed above this
I’m not sure why my controller code is caching the query instead of the result. Any advice would be greatly appreciated.
IIRC ActiveRecord is now “lazy”, and you’re just caching the query object. Try appending .all after User.paginate() to force the sql to run, giving you a result set to cache.
If .all fails, try .map/.select/.inject instead.