40 lines
1.9 KiB
Markdown
40 lines
1.9 KiB
Markdown
+++
|
|
date = "2007-12-06"
|
|
title = "Rails: calculated column caching"
|
|
tags = ["Blog", "Features", "Ruby", "Ruby on Rails", "Rails", "cache", "sort", "order", "find", "select", "join"]
|
|
slug = "rails-calculated-column-caching"
|
|
description = "Save on query time by caching calculated column values."
|
|
+++
|
|
|
|
Sometimes you're working on a Rails project and you think: "hey! This should be easy!". Well, most of the time it is. I'm working on a project that allows people to rate objects (what they really are doesn't matter at all).
|
|
|
|
I'm using the <a href="http://juixe.com/svn/acts_as_rateable">acts_as_rateable plugin</a> which creates an extra database table containing all ratings. I also have a table with my objects. Using the plugin I'm now able to do the following:
|
|
|
|
<pre lang="ruby">obj = Object.find(:first)
|
|
obj.add_rating Rating.new(:rating => 4)
|
|
obj.add_rating Rating.new(:rating => 5)
|
|
obj.rating
|
|
=> 4.5</pre>
|
|
|
|
This works all perfectly, until you want to sort objects by rating. You could construct a huge SQL query to join the two tables, but that's not really efficient, especially when your database gets bigger.
|
|
|
|
The solution is very easy and even more elegant. Use a cache! For this, you'll first have to add a new field to the objects table. Do this in a migration:
|
|
|
|
<pre lang="ruby">add_column :objects, :rating_cache, :float</pre>
|
|
|
|
Now, in the Object model, add the following method:
|
|
|
|
<pre lang="ruby">def rate_with(rating)
|
|
add_rating(rating)
|
|
update_attribute('rating_cache', self.rating)
|
|
end</pre>
|
|
|
|
You'll need to change your controller from using #add_rating to #rate_with. The syntax is exactly the same. Now, when you add a rating, we also store the average rating in the rating_cache column.
|
|
|
|
To get back to the sorting problem, you can now use the rating_cache column to sort Objects.
|
|
|
|
<pre lang="ruby">Object.find(:all, :order => 'rating_cache DESC')</pre>
|
|
|
|
Of course, you can use this trick on all sorts of relations. Have fun with it.
|
|
|