Skip to main content

Rails: calculated column caching

·243 words·2 mins· ·
Blog Features Ruby Ruby on Rails Rails Cache Sort Order Find Select Join
Ariejan de Vroom
Author
Ariejan de Vroom
Jack of all Trades, Professional Software Craftsman

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 acts_as_rateable plugin 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:

obj = Object.find(:first)
obj.add_rating Rating.new(:rating => 4)
obj.add_rating Rating.new(:rating => 5)
obj.rating
=> 4.5

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:

add_column :objects, :rating_cache, :float

Now, in the Object model, add the following method:

def rate_with(rating)
  add_rating(rating)
  update_attribute('rating_cache', self.rating)
end

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.

Object.find(:all, :order => 'rating_cache DESC')

Of course, you can use this trick on all sorts of relations. Have fun with it.

Related

RailsJobs.nl - Ruby on Rails Jobs in The Netherlands
·175 words·1 min
General Blog Ruby Ruby on Rails Rails Jobs RailsJobs.nl
Bash it! - Number of messages in Postfix queue
·37 words·1 min
Blog Features Linux Bash Bash IT Shell Postfix Scripting Mail Server Queue Email Messages
Using Iconv to convert UTF-8 to ASCII (on Linux)
·207 words·1 min
General RubyOnRails Features Ruby