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 singleid
, as infind
(id)
, but it can also be called with an array ofid
s, likefind
(id1, id2, id3, ...
) in which casefind
will return an array of values. Finally, you can callfind
([id1, id2])
and retrieve everything withid
values betweenid1
andid2
.- find all
Calling
find
with an argument of:all
will return all the matching values as an array. (You can also abbreviatefind(: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 abbreviatefind(: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 withfind(:first)
, you’ll probably want to specify:order
to be certain which value you get. (Again, you can abbreviatefind(: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 oftrue
.: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 ofemail
, after sanitizing it.:order
The
:order
option lets you choose the order in which records are returned, though if you’re usingfind(:first)
orfind(: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 sortfamily_name
values in ascending order, usinggiven_name
as a second sort field whenfamily_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
: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.