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:
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 id
s, 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
.
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.)
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.)
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
: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
.