Finding Data with ActiveRecord

The find method is common in Rails, usually in controllers. It’s constantly used as find(id) to retrieve a single record with a given id, and also used as find(:all) to retrieve an entire set of records. The find method is, however, capable of much more finesse, letting you control which records are returned and in what order. There are four basic ways to call find, and then a set of options that can apply to all of those uses:

find by id

The find method is frequently called with a single id, as in find(id), but it can also be called with an array of ids, like find (id1, id2, id3, ...) in which case find will return an array of values. Finally, you can call find ([id1, id2]) and retrieve everything with id values between id1 and id2.

find all

Calling find with an argument of :all will return all the matching values as an array. (You can also abbreviate find(:all) to just .all—User.all, for example.)

find first

Calling find with an argument of :first will return the first matching value only. You’ll probably want to specify :order to be certain which value you get. (You can also abbreviate find(:first) to just .first—User.first, for example.)

find last

Calling find with an argument of :last will return the last matching value only. As with find(:first), you’ll probably want to specify :order to be certain which value you get. (Again, you can abbreviate find(:last) to just .last—User.last, for example.)

The options give you much more control over what is queried and which values are returned. All of them actually modify the SQL statements used to query the database and can accept SQL syntax, but you don’t need to know SQL to use most of them. This list of options is sorted by your likely order of needing them:

:conditions

The :conditions option lets you limit which records are returned. If, for example, you set:

find(:all, :conditions => "registered = true")

then you would only see records with a registered value of true. :conditions also has another form. You could instead write:

find(:all, :conditions => { :registered => true })

This will produce the same query and makes it a little more readable to list multiple conditions. Also, if conditions are coming in from a parameter or some other data source you don’t entirely trust, you may want to use the array form of :conditions:

find(:all, :conditions => ["email = ?", email])

Rails will replace the ? with the value of email, after sanitizing it.

:order

The :order option lets you choose the order in which records are returned, though if you’re using find(:first) or find(:last) it will also determine which record you’ll see as first or last. The simplest way to use this is with a field name or comma-separated list of field names:

find(:all, :order => "family_name, given_name")

By default, the :order option will sort in ascending order, so the option just shown would sort family_name values in ascending order, using given_name as a second sort field when family_name values are the same. If you want to sort in descending order, just put DESC after the field name:

find(:all, :order => "family_name DESC, given_name DESC")

This will return the names sorted in descending order.

:limit

The :limit option lets you specify how many records are returned. If you wrote:

find(:all, :limit => 10)

you would receive only the first 10 records back. (You’ll probably want to specify :order to ensure that they’re the ones you want.)

:offset

The :offset option lets you specify a starting point from which records should be returned. If, for instance, you wanted to retrieve the next 10 records after a set you’d retrieved with :limit, you could specify:

find(:all, :limit => 10, :offset => 10)
:readonly

Retrieves records so that you can read them, but cannot make any changes.

:group

The :group option lets you specify a field that the results should group on, like the SQL GROUP BY clause.

:lock

Lets you test for locked rows.

:joins, :include, :select, and :from

These let you specify components of the SQL query more precisely. You may need them as you delve into complex data structures, but you can ignore them at first.

Rails also offers dynamic finders, which are methods it automatically supports based on the names of the fields in the database. If you have a given_name field, for example, you can call find_by_given_name(name) to get the first record with the specified name, or find_all_by_given_name(name) to get all records with the specified name. These are a little slower than the regular find method, but may be more readable.

Rails 2.1 and later versions also offer an elegant way to create more readable queries with the named_scope method for defining queries specific to particular models, which you should explore after you’ve found your way around find.

Get Learning Rails: Live Edition now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.