Skip to content

Commit

Permalink
Improve structure at the beginning of the AR Finders guide
Browse files Browse the repository at this point in the history
  • Loading branch information
lifo committed Feb 7, 2009
1 parent 01f82d6 commit 9fd8538
Showing 1 changed file with 84 additions and 47 deletions.
131 changes: 84 additions & 47 deletions railties/guides/source/active_record_querying.textile
Expand Up @@ -16,6 +16,10 @@ If you're used to using raw SQL to find database records then, generally, you wi

Code examples throughout this guide will refer to one or more of the following models:

TIP: All of the following models uses +id+ as the primary key, unless specified otherwise.

<br />

<ruby>
class Client < ActiveRecord::Base
has_one :address
Expand Down Expand Up @@ -48,85 +52,118 @@ class Role < ActiveRecord::Base
end
</ruby>

bq. Active Record will perform queries on the database for you and is compatible with most database systems (MySQL, PostgreSQL and SQLite to name a few). Regardless of which database system you're using, the Active Record method format will always be the same.
Active Record will perform queries on the database for you and is compatible with most database systems (MySQL, PostgreSQL and SQLite to name a few). Regardless of which database system you're using, the Active Record method format will always be the same.

h3. Retrieving objects
h3. Retrieving objects from the database

To retrieve objects from the database, Active Record provides a primary method called +find+. This method allows you to pass arguments into it to perform certain queries on your database without the need of SQL. If you wanted to find the record with the id of 1, you could type +Client.find(1)+ which would execute this query on your database:
To retrieve objects from the database, Active Record provides a class method called +Model.find+. This method allows you to pass arguments into it to perform certain queries on your database without the need of writing raw SQL.

<sql>
SELECT * FROM clients WHERE (clients.id = 1)
</sql>
Primary operation of <tt>Model.find(options)</tt> can be summarized as:

* Convert the supplied options to an equivalent SQL query.
* Fire the SQL query and retrieve the corresponding results from the database.
* Instantiate the equivalent Ruby object of the appropriate model for every resulting row.
* Run +after_find+ callbacks if any.

h4. Retrieving a Single Object

NOTE: Because this is a standard table created from a migration in Rails, the primary key is defaulted to 'id'. If you have specified a different primary key in your migrations, this is what Rails will find on when you call the find method, not the id column.
Active Record lets you retrieve a single object using three different ways.

h5. Using a primary key

Using <tt>Model.find(primary_key)</tt>, you can retrieve the object corresponding to the supplied _primary key_. For example:

<ruby>
# Find the client with primary key (id) 10.
client = Client.find(10)
=> #<Client id: 10, name: => "Ryan">
</ruby>

If you wanted to find clients with id 1 or 2, you call +Client.find([1,2])+ or +Client.find(1,2)+ and then this will be executed as:
SQL equivalent of the above is:

<sql>
SELECT * FROM clients WHERE (clients.id IN (1,2))
SELECT * FROM clients WHERE (clients.id = 10)
</sql>

<shell>
>> Client.find(1,2)
=> [#<Client id: 1, name: => "Ryan", locked: false, orders_count: 2,
created_at: "2008-09-28 15:38:50", updated_at: "2008-09-28 15:38:50">,
#<Client id: 2, name: => "Michael", locked: false, orders_count: 3,
created_at: "2008-09-28 13:12:40", updated_at: "2008-09-28 13:12:40">]
</shell>

Note that if you pass in a list of numbers that the result will be returned as an array, not as a single Client object.
<tt>Model.find(primary_key)</tt> will raise an +ActiveRecord::RecordNotFound+ exception if no matching record is found.

NOTE: If +find(id)+ or +find([id1, id2])+ fails to find any records, it will raise a RecordNotFound exception.
h5. Find First

If you wanted to find the first Client object you would simply type +Client.first+ and that would find the first client in your clients table:
<tt>Model.first(options = nil)</tt> finds the first record matched by the supplied options. If no +options+ are supplied, the first matching record is returned. For example:

<shell>
>> Client.first
=> #<Client id: 1, name: => "Ryan", locked: false, orders_count: 2,
created_at: "2008-09-28 15:38:50", updated_at: "2008-09-28 15:38:50">
</shell>
<ruby>
# Find the client with primary key (id) 10.
client = Client.first
=> #<Client id: 1, name: => "Lifo">
</ruby>

If you were reading your log file (the default is log/development.log) you may see something like this:
SQL equivalent of the above is:

<sql>
SELECT * FROM clients LIMIT 1
</sql>

Indicating the query that Rails has performed on your database.
<tt>Model.first</tt> returns +nil+ if no matching record is found. No exception will be raised.

To find the last Client object you would simply type +Client.last+ and that would find the last client created in your clients table:
NOTE: +Model.find(:first, options)+ is equivalent to +Model.first(options)+

<shell>
>> Client.last
=> #<Client id: 2, name: => "Michael", locked: false, orders_count: 3,
created_at: "2008-09-28 13:12:40", updated_at: "2008-09-28 13:12:40">
</shell>
h5. Find Last

If you were reading your log file (the default is log/development.log) you may see something like this:
<tt>Model.last(options = nil)</tt> finds the last record matched by the supplied options. If no +options+ are supplied, the last matching record is returned. For example:

<ruby>
# Find the client with primary key (id) 10.
client = Client.last
=> #<Client id: 221, name: => "Russel">
</ruby>

SQL equivalent of the above is:

<sql>
SELECT * FROM clients ORDER BY id DESC LIMIT 1
SELECT * FROM clients ORDER BY clients.id DESC LIMIT 1
</sql>

NOTE: Please be aware that the syntax that Rails uses to find the first record in the table means that it may not be the actual first record. If you want the actual first record based on a field in your table (e.g. +created_at+) specify an order option in your find call. The last method call works differently: it finds the last record on your table based on the primary key column.
<tt>Model.last</tt> returns +nil+ if no matching record is found. No exception will be raised.

NOTE: +Model.find(:last, options)+ is equivalent to +Model.last(options)+

h4. Retrieving Multiple Objects

h5. Using multiple primary keys

<tt>Model.find(array_of_primary_key)</tt> also accepts an array of _primary keys_. An array of all the matching records for the supplied _primary keys_ is returned. For example:

<ruby>
# Find the clients with primary keys 1 and 10.
client = Client.find(1, 10) # Or even Client.find([1, 10])
=> [#<Client id: 1, name: => "Lifo">, #<Client id: 10, name: => "Ryan">]
</ruby>

SQL equivalent of the above is:

<sql>
SELECT * FROM clients ORDER BY clients.id DESC LIMIT 1
SELECT * FROM clients WHERE (clients.id IN (1,10))
</sql>

To find all the Client objects you would simply type +Client.all+ and that would find all the clients in your clients table:
<tt>Model.find(array_of_primary_key)</tt> will raise an +ActiveRecord::RecordNotFound+ exception unless a matching record is found for <strong>all</strong> of the supplied primary keys.

<shell>
>> Client.all
=> [#<Client id: 1, name: => "Ryan", locked: false, orders_count: 2,
created_at: "2008-09-28 15:38:50", updated_at: "2008-09-28 15:38:50">,
#<Client id: 2, name: => "Michael", locked: false, orders_count: 3,
created_at: "2008-09-28 13:12:40", updated_at: "2008-09-28 13:12:40">]
</shell>
h5. Find All

<tt>Model.all(options = nil)</tt> finds all the records matching the supplied +options+. If no +options+ are supplied, all rows from the database are returned.

<ruby>
# Find all the clients.
client = Client.all
=> [#<Client id: 1, name: => "Lifo">, #<Client id: 10, name: => "Ryan">, #<Client id: 221, name: => "Russel">]
</ruby>

And the equivalent SQL is:

You may see in Rails code that there are calls to methods such as +Client.find(:all)+, +Client.find(:first)+ and +Client.find(:last)+. These methods are just alternatives to +Client.all+, +Client.first+ and +Client.last+ respectively.
<sql>
SELECT * FROM clients
</sql>

Be aware that +Client.first+/+Client.find(:first)+ and +Client.last+/+Client.find(:last)+ will both return a single object, where as +Client.all+/+Client.find(:all)+ will return an array of Client objects, just as passing in an array of ids to +find+ will do also.
<tt>Model.all</tt> returns an empty array +[]+ if no matching record is found. No exception will be raised.

h3. Conditions

Expand Down

0 comments on commit 9fd8538

Please sign in to comment.