Over the last two episodes we’ve shown you how to set up your computer for Rails 3 and create new Rails 3 applications. In this episode we’ll begin looking at some of its new features, starting with ActiveRecord which provides a new interface for performing database queries. Pratik Naik went into this subject in detail in a post on his blog recently which is well worth reading.

Some Basic Examples

To start we’ll show you a few examples of old ActiveRecord find calls and convert them into the new query format. For this we’ll be using a basic Rails application that has two models: Article and Comment that have a relationship whereby an Articlehas_many :comments.

The first find we’ll update returns the ten most recently published articles.

ruby

Article.find(:all, :order => "published_at desc", :limit => 10)

The basic approach to converting an ActiveRecord query to the new Rails 3 format is to look at the hash of options that’s being passed to find and to replace each item in the hash with an equivalent method. So, instead of the find call above we can use:

ruby

Article.order("published_at desc").limit(10)

As you can see the new syntax is easy to convert from the old Rails find but has a neater syntax.

The old hash options don’t always map exactly onto the new methods however as we’ll demonstrate in this next example.

There are only two real exceptions to the rule and conveniently the example above uses them both. The find above will get all of the articles that have a published date before the current time along with any associated comments. In Rails 3 this becomes:

ruby

Article.where("published_at <= ?", Time.now).includes(:comments)

Instead of :conditions we now use the where method, passing in the same arguments as we would to :conditions. The arguments can be passed as an array but it’s cleaner to pass them separately. For getting associated records :include gets pluralized to become the includes method. All of the other options we’d normally pass to find become methods with the same name as the option.

Our final example fetches the most recently published article.

ruby

Article.find(:first, :order => "published_at desc")

Using the Rails 3 syntax this becomes:

ruby

Article.order("published_at desc").first()

Note that we don’t call first until the end of the method chain.

As we’re fetching in descending order we could rewrite the line above as:

ruby

Article.order("published_at").last()

This will perform the same query but with slightly more concise code.

In Rails 3.0 we can use either the old find methods or the new Rails 3 syntax but in Rails 3.1 the old methods will be deprecated and from Rails 3.2 they will be removed completely. It’s well worth rewriting your finds as you migrate your applications to Rails 3 so that your applications will be compatible with future releases of Rails 3.

You might be wondering at this point just what the point of this new syntax is, especially as it will break a lot of existing Rails applications when they are upgraded. Well there is a purpose to this change and it lies in the power of lazy loading.

Lazy Loading

To demonstrate lazy loading we’ll use our application’s console. If we ask for all of the articles we’ll get an array returned as we’d expect and we’ll see that we have three articles in our database.

Instead of a list of articles being returned this time we have an ActiveRecord::Relation object. This object stores information about our find, but the database query hasn’t yet been made. This is what is meant by lazy loading in this context: the data isn’t loaded until it has to be. If we were to enumerate through the records with each or get all or just the first of the articles then the query will be made.

Now let’s see how this applies to our application. We’ve generated a scaffold for the article model so we have an articles controller with the usual seven actions. The code for the index action uses Article.all to get all of the articles immediately:

If we use use any of the find options on the articles, such as ordering by name then an ActiveRecord::Relation object will be returned instead and the query will not be performed in the controller. The database query will instead be performed in the view code when we enumerate through each Article.

If we load the index page now the articles will be shown in alphabetical order.

The nice thing about this is that if you’re using fragment caching with the cache method in your view this will now work better as the database query will not be performed unless it is necessary.

The new query syntax makes it easier to build up find conditions. Let’s say we want to filter the articles so that only the hidden ones are shown if we have hidden=1 in the URL’s query string. We can do that by modifying the index action like this:

Now we check that the there is a hidden parameter passed and if there is we add a where method to the find that will show only the hidden articles if that hidden parameter has a value of 1. If we append that parameter to the URL and reload the page we’ll see just the hidden articles.

Likewise if we pass 0 we’ll see only the visible articles.

Being able to chain together methods like this is a nice way to be able to build up more complex database queries while knowing that the query won’t actually be executed until the data is needed.

Named Scopes

Next we’ll show you some of the changes to named scopes in Rails 3. Below is our Article model with two named scopes, one to fetch the visible articles and one to fetch the articles that have been published.

These named scopes are defined as we’d define them in a Rails 2 application but the Rails 3 approach is a little different. The first difference is that the method to define a named scope is no longer named_scope but just scope. Also we no longer pass the conditions as a hash but, as with find, we use now use methods. Like we did with the new find methods we use where instead of :conditions. In the Rails 3 syntax the named scopes will look like this:

Another new feature is the ability to build up scopes. If we want to create a scope called recent that will return the recently published visible articles ordered by their publish date we can do so by reusing the two scopes we already have.

ruby

scope :recent, visible.published.order("published_at desc")

What we’ve done in our new scope is chain together the two scopes we already have an add an order method to create a new scope and this chaining ability is a very powerful feature to have when creating scopes for our models.

We can try our new named scope in the console. If we call Article.recent an ActiveRecord::NamedScope::Scope object is returned. This is an object that behaves in a similar way to the ActiveRecord::Relation object we saw earlier.

This shows the SQL that ActiveRecord will perform to return the recently published articles that are not hidden.

That’s it for this episode on using ActiveRecord queries in Rails 3. There are a lot of great additions that will make the code in your Rails controllers more concise and expressive. Any time spent playing with the new features will soon repay itself.