Programming - - By Louis Simoneau

Checking out the Rails 3 beta, Part III: The Query API

In my last two posts I’ve introduced you to some of my favourite new features in the beta version of Ruby on Rails 3.0: the Bundler gem manager and the new routing module. I think it’s fair to say I’ve saved the best for last: this week I’m delving into the changes to the ActiveRecord query API.

Arguably the core of Rails is ActiveRecord, its Object-Relational Mapping (ORM) library. Although a lot of work has gone in to decoupling the components of Rails 3.0 so that you can in principle use whichever ORM you prefer, ActiveRecord is still the default.
ActiveRecord provides you with ways of creating new models, saving them to the database, updating them, deleting them, and retrieving their information. However, the new features in Rails 3 are primarily related to the way in which you query the database for collections of models, so that’s what I’ll focus on here. Let’s first look at the old way of doing that. If you wanted the 10 most recent articles in the ‘gardening’ category, as well as their associated comments, you used to write:

Article.find(:all, :limit => 10, :conditions => {:category => "gardening"}, :order => "created_at DESC", :include => :comments) 

You call the find method, specify that you want a collection with the :all parameter, then pass in a bunch of options. The new syntax relies instead on chaining a number of methods together, rather than passing in all those options to the find method. So, to retrieve those same articles and their comments, you’d now write:

recent = Article.where(:category => "gardening").order("created_at DESC").limit(10).includes(:comments)

Each of those methods–where, order, limit, and includes–returns a new type of object called a relation. The relation behaves just like the model object does, which is why you can chain as many of those methods together as you’d like. The cool thing here is that the code above hasn’t actually run an SQL query. It’s just remembering everything you’re trying to select in the form of this relation object. The query is only executed when you need to access the contents of the selection.

Let’s say I then wrote:

recent.each { |a| puts a.title }

The database query would be run and each article’s title would be printed in sequence to the console. This new chained syntax is more readable, allows you a lot more flexibility when playing with collections of your models, and also makes some forms of caching more effective (since certain actions in controllers will no longer need to perform database queries, their results can be effectively cached.)

Of course, I’ve just scratched the surface of the new query API in Rails 3. You can read a much more detailed account on Pratik’s blog.

What’s more, the features I covered in this series are only a few of the new features in Rails 3 (albeit the flashiest ones in my opinion!) If it’s been awhile since you peeked into the Rails universe, there’s no time like the present to get reacquainted.