Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to cache a query in Ruby on Rails 3

I have the following query in my application

@categories = Category.joins(:posts).select('distinct categories.*').order('label')

This query gets loaded on every page view since the categories are displayed on every page. This seems messy to me since the list of categories are not getting updated that often. Is there a nifty way to cache just the query? I have tried

   Category.cache do
      @categories = Category.joins(:posts).select('distinct categories.*').order('label')
    end

but I still see the query getting loaded every time from the database in the development log.

like image 751
Jason Yost Avatar asked Apr 18 '11 22:04

Jason Yost


People also ask

How do I cache a query?

You can create a Cached Query right from the Explorer. To cache a query, go ahead and save the query first. Fig 1: Press the button to "Save" the query. Then, to cache your most important queries select the “Enable Caching” checkbox and enter a refresh rate.

How do you implement cache in Ruby?

In order to use page and action caching you will need to add actionpack-page_caching and actionpack-action_caching to your Gemfile . By default, caching is only enabled in your production environment. You can play around with caching locally by running rails dev:cache , or by setting config. action_controller.

What is cache sweeper in rails?

Cache sweeping is a mechanism which allows you to get around having a ton of expire_{page,action,fragment} calls in your code. It does this by moving all the work required to expire cached content into na ActionController::Caching::Sweeper class.

Where is Rails cache stored?

Page caches are always stored on disk. Rails 2.1 and above provide ActiveSupport::Cache::Store which can be used to cache strings. Some cache store implementations, like MemoryStore, are able to cache arbitrary Ruby objects, but don't count on every cache store to be able to do that.


2 Answers

In your controller, you can try something like:

@categories = Rails.cache.fetch('categories', :expires_in => 24.hours) { Category.joins(:posts).select('distinct categories.*').order('label') }

Which will only read to see if the following data block 'categories' has been cached and not expired. If expired after 24 hours, will then query the model and write the new record into Rails cache.

For more information, I followed the following guide.

Try it out. I have it working this way. Hope that helps.

like image 146
Christian Fazzini Avatar answered Oct 02 '22 08:10

Christian Fazzini


You can use fragment caching for the part of your view template that displays the categories. This means that the categories will be served from the cache store and the query will only be executed once until the cache is expired (by using the expire_fragment method).

  • Fragment Caching Rails Guide
like image 29
John Topley Avatar answered Oct 02 '22 09:10

John Topley