Brian Landau, Web Developer, August 07, 2008
When working on high-traffic Rails sites, it often becomes necessary to find ways to improve performance with caching. One place we’ve found this is most convenient and easy-to-do is by caching an ActiveRecord result set for models that change rarely or not at all. An easy example of this is a Category model.
Often times, you have a categorization hierarchy that will never or rarely change over the life of an application. Ideally you would fetch the results once from the database and never have to again. So how do we go about caching this? First let’s look at our model and create a named_scope for it:
class Category < ActiveRecord::Base
acts_as_tree
named_scope :find_top_level, :conditions => 'categories.parent_id IS NULL',
:order => 'categories.name'
end
Next, we need to create create a method that fetches the results for our new scope and caches it in a class variable. It should also only do caching if in production environment (alternatively or additionally, we could use the ActionController.perform_caching config value), as this can cause problems in tests.
def self.top_level
unless ('production' == RAILS_ENV) && ActionController.perform_caching
@@top_level_cache = self.find_top_level
else
@@top_level_cache ||= self.find_top_level
end
end
Finally, we need to create a method to invalidate our cache when records are saved or deleted. Since we know this isn’t happening often (if at all), this should rarely be performed but is a good safeguard so we know our cache is current.
after_save :reset_cached_finder
after_destroy :reset_cached_finder
def reset_cached_finder
@@top_level_cache = nil
end
This is something that we could easily see doing in a number of models for a number of finders. Since this involves a lot of similar code, it would be great if we could create some meta code that would allow us to define these caches with a simple one liner.
Continue reading "Named Scope Caching"
Recent Comments
Tony,
I understand and agree that the back-end shouldn’t output code (html code), and only content. The templates (aka views) should do the trick, but instead of having lot’s of if/else conditionals inside the view, you may just output the following content.
No information available
The template would loop in an array and put all the <li>’s inside the <ul>.
I don’t see anything wrong, nor...