active_record_querying.md 52.1 KB
Newer Older
1 2
Active Record Query Interface
=============================
3 4 5 6 7 8 9 10 11

This guide covers different ways to retrieve data from the database using Active Record. By referring to this guide, you will be able to:

* Find records using a variety of methods and conditions
* Specify the order, retrieved attributes, grouping, and other properties of the found records
* Use eager loading to reduce the number of database queries needed for data retrieval
* Use dynamic finders methods
* Check for the existence of particular records
* Perform various calculations on Active Record models
X
Xavier Noria 已提交
12
* Run EXPLAIN on relations
13

14
--------------------------------------------------------------------------------
15

16
If you're used to using raw SQL to find database records, then you will generally find that there are better ways to carry out the same operations in Rails. Active Record insulates you from the need to use SQL in most cases.
17 18 19

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

J
Joe Hannon 已提交
20
TIP: All of the following models use +id+ as the primary key, unless specified otherwise.
21

22
```ruby
23 24 25 26 27
class Client < ActiveRecord::Base
  has_one :address
  has_many :orders
  has_and_belongs_to_many :roles
end
28
```
29

30
```ruby
31 32 33
class Address < ActiveRecord::Base
  belongs_to :client
end
34
```
35

36
```ruby
37 38 39
class Order < ActiveRecord::Base
  belongs_to :client, :counter_cache => true
end
40
```
41

42
```ruby
43 44 45
class Role < ActiveRecord::Base
  has_and_belongs_to_many :clients
end
46
```
47

48
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.
49

50 51
Retrieving Objects from the Database
------------------------------------
52

53
To retrieve objects from the database, Active Record provides several finder methods. Each finder method allows you to pass arguments into it to perform certain queries on your database without writing raw SQL.
54 55

The methods are:
56 57
* +bind+
* +create_with+
O
Oscar Del Ben 已提交
58
* +eager_load+
59 60
* +extending+
* +from+
61
* +group+
62
* +having+
63
* +includes+
64 65
* +joins+
* +limit+
66
* +lock+
O
Oscar Del Ben 已提交
67
* +none+
68 69 70
* +offset+
* +order+
* +none+
O
Oscar Del Ben 已提交
71
* +preload+
72
* +readonly+
73 74 75 76 77 78
* +references+
* +reorder+
* +reverse_order+
* +select+
* +uniq+
* +where+
79

80
All of the above methods return an instance of <tt>ActiveRecord::Relation</tt>.
81

82
The primary operation of <tt>Model.find(options)</tt> can be summarized as:
83 84 85 86

* 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.
87
* Run +after_find+ callbacks, if any.
88

89
### Retrieving a Single Object
90

91
Active Record provides five different ways of retrieving a single object.
92

93
#### Using a Primary Key
94

95
Using <tt>Model.find(primary_key)</tt>, you can retrieve the object corresponding to the specified _primary key_ that matches any supplied options. For example:
96

97
```ruby
98 99
# Find the client with primary key (id) 10.
client = Client.find(10)
100
# => #<Client id: 10, first_name: "Ryan">
101
```
102

103
The SQL equivalent of the above is:
104

105
```sql
106
SELECT * FROM clients WHERE (clients.id = 10) LIMIT 1
107
```
108

109
<tt>Model.find(primary_key)</tt> will raise an +ActiveRecord::RecordNotFound+ exception if no matching record is found.
110

111
#### +take+
112

113
<tt>Model.take</tt> retrieves a record without any implicit ordering. For example:
114

115
```ruby
116 117
client = Client.take
# => #<Client id: 1, first_name: "Lifo">
118
```
119 120 121

The SQL equivalent of the above is:

122
```sql
123
SELECT * FROM clients LIMIT 1
124
```
125

126 127 128
<tt>Model.take</tt> returns +nil+ if no record is found and no exception will be raised.

TIP: The retrieved record may vary depending on the database engine.
129

130
#### +first+
131

132
<tt>Model.first</tt> finds the first record ordered by the primary key. For example:
133

134
```ruby
135
client = Client.first
136
# => #<Client id: 1, first_name: "Lifo">
137
```
138

139
The SQL equivalent of the above is:
140

141
```sql
142
SELECT * FROM clients ORDER BY clients.id ASC LIMIT 1
143
```
144

145
<tt>Model.first</tt> returns +nil+ if no matching record is found and no exception will be raised.
146

147
#### +last+
148

149
<tt>Model.last</tt> finds the last record ordered by the primary key. For example:
150

151
```ruby
152
client = Client.last
153
# => #<Client id: 221, first_name: "Russel">
154
```
155

156
The SQL equivalent of the above is:
157

158
```sql
159
SELECT * FROM clients ORDER BY clients.id DESC LIMIT 1
160
```
161

162
<tt>Model.last</tt> returns +nil+ if no matching record is found and no exception will be raised.
163

164
#### +find_by+
165 166 167

<tt>Model.find_by</tt> finds the first record matching some conditions. For example:

168
```ruby
169 170 171 172 173
Client.find_by first_name: 'Lifo'
# => #<Client id: 1, first_name: "Lifo">

Client.find_by first_name: 'Jon'
# => nil
174
```
175 176 177

It is equivalent to writing:

178
```ruby
179
Client.where(first_name: 'Lifo').take
180
```
181

182
#### +take!+
183 184 185

<tt>Model.take!</tt> retrieves a record without any implicit ordering. For example:

186
```ruby
187 188
client = Client.take!
# => #<Client id: 1, first_name: "Lifo">
189
```
190 191 192

The SQL equivalent of the above is:

193
```sql
194
SELECT * FROM clients LIMIT 1
195
```
196

197
<tt>Model.take!</tt> raises +ActiveRecord::RecordNotFound+ if no matching record is found.
198

199
#### +first!+
200

201
<tt>Model.first!</tt> finds the first record ordered by the primary key. For example:
202

203
```ruby
204
client = Client.first!
205
# => #<Client id: 1, first_name: "Lifo">
206
```
207

208
The SQL equivalent of the above is:
209

210
```sql
211
SELECT * FROM clients ORDER BY clients.id ASC LIMIT 1
212
```
213

214
<tt>Model.first!</tt> raises +ActiveRecord::RecordNotFound+ if no matching record is found.
215

216
#### +last!+
217

218
<tt>Model.last!</tt> finds the last record ordered by the primary key. For example:
219

220
```ruby
221
client = Client.last!
222
# => #<Client id: 221, first_name: "Russel">
223
```
224

225
The SQL equivalent of the above is:
226

227
```sql
228
SELECT * FROM clients ORDER BY clients.id DESC LIMIT 1
229
```
230

231
<tt>Model.last!</tt> raises +ActiveRecord::RecordNotFound+ if no matching record is found.
232

233
#### +find_by!+
234

235
<tt>Model.find_by!</tt> finds the first record matching some conditions. It raises +ActiveRecord::RecordNotFound+ if no matching record is found. For example:
236

237
```ruby
238 239 240 241
Client.find_by! first_name: 'Lifo'
# => #<Client id: 1, first_name: "Lifo">

Client.find_by! first_name: 'Jon'
242
# => ActiveRecord::RecordNotFound
243
```
244 245 246

It is equivalent to writing:

247
```ruby
248
Client.where(first_name: 'Lifo').take!
249
```
250

251
### Retrieving Multiple Objects
252

253
#### Using Multiple Primary Keys
254

255
<tt>Model.find(array_of_primary_key)</tt> accepts an array of _primary keys_, returning an array containing all of the matching records for the supplied _primary keys_. For example:
256

257
```ruby
258
# Find the clients with primary keys 1 and 10.
259
client = Client.find([1, 10]) # Or even Client.find(1, 10)
260
# => [#<Client id: 1, first_name: "Lifo">, #<Client id: 10, first_name: "Ryan">]
261
```
262

263
The SQL equivalent of the above is:
264

265
```sql
266
SELECT * FROM clients WHERE (clients.id IN (1,10))
267
```
268

269
WARNING: <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.
270

271
#### take
272 273 274

<tt>Model.take(limit)</tt> retrieves the first number of records specified by +limit+ without any explicit ordering:

275
```ruby
276
Client.take(2)
V
Vijay Dev 已提交
277
# => [#<Client id: 1, first_name: "Lifo">,
278
      #<Client id: 2, first_name: "Raf">]
279
```
280 281 282

The SQL equivalent of the above is:

283
```sql
284
SELECT * FROM clients LIMIT 2
285
```
286

287
#### first
288 289 290

<tt>Model.first(limit)</tt> finds the first number of records specified by +limit+ ordered by primary key:

291
```ruby
292
Client.first(2)
V
Vijay Dev 已提交
293
# => [#<Client id: 1, first_name: "Lifo">,
294
      #<Client id: 2, first_name: "Raf">]
295
```
296 297 298

The SQL equivalent of the above is:

299
```sql
300
SELECT * FROM clients LIMIT 2
301
```
302

303
#### last
304 305 306

<tt>Model.last(limit)</tt> finds the number of records specified by +limit+ ordered by primary key in descending order:

307
```ruby
308
Client.last(2)
V
Vijay Dev 已提交
309
# => [#<Client id: 10, first_name: "Ryan">,
310
      #<Client id: 9, first_name: "John">]
311
```
312 313 314

The SQL equivalent of the above is:

315
```sql
316
SELECT * FROM clients ORDER By id DESC LIMIT 2
317
```
318

319
### Retrieving Multiple Objects in Batches
320

321
We often need to iterate over a large set of records, as when we send a newsletter to a large set of users, or when we export data.
322

323
This may appear straightforward:
324

325
```ruby
326
# This is very inefficient when the users table has thousands of rows.
P
Pratik Naik 已提交
327
User.all.each do |user|
328 329
  NewsLetter.weekly_deliver(user)
end
330
```
331

332
But this approach becomes increasingly impractical as the table size increases, since +User.all.each+ instructs Active Record to fetch _the entire table_ in a single pass, build a model object per row, and then keep the entire array of model objects in memory. Indeed, if we have a large number of records, the entire collection may exceed the amount of memory available.
333

334
Rails provides two methods that address this problem by dividing records into memory-friendly batches for processing. The first method, +find_each+, retrieves a batch of records and then yields _each_ record to the block individually as a model. The second method, +find_in_batches+, retrieves a batch of records and then yields _the entire batch_ to the block as an array of models.
335 336

TIP: The +find_each+ and +find_in_batches+ methods are intended for use in the batch processing of a large number of records that wouldn't fit in memory all at once. If you just need to loop over a thousand records the regular find methods are the preferred option.
337

338
#### +find_each+
339

340
The +find_each+ method retrieves a batch of records and then yields _each_ record to the block individually as a model. In the following example, +find_each+ will retrieve 1000 records (the current default for both +find_each+ and +find_in_batches+) and then yield each record individually to the block as a model. This process is repeated until all of the records have been processed:
341

342
```ruby
343 344 345
User.find_each do |user|
  NewsLetter.weekly_deliver(user)
end
346
```
347

348
##### Options for +find_each+
349 350

The +find_each+ method accepts most of the options allowed by the regular +find+ method, except for +:order+ and +:limit+, which are reserved for internal use by +find_each+.
351

352
Two additional options, +:batch_size+ and +:start+, are available as well.
353

354 355 356
*+:batch_size+*

The +:batch_size+ option allows you to specify the number of records to be retrieved in each batch, before being passed individually to the block. For example, to retrieve records in batches of 5000:
357

358
```ruby
359 360 361
User.find_each(:batch_size => 5000) do |user|
  NewsLetter.weekly_deliver(user)
end
362
```
363

364
*+:start+*
365

366
By default, records are fetched in ascending order of the primary key, which must be an integer. The +:start+ option allows you to configure the first ID of the sequence whenever the lowest ID is not the one you need. This would be useful, for example, if you wanted to resume an interrupted batch process, provided you saved the last processed ID as a checkpoint.
367

368
For example, to send newsletters only to users with the primary key starting from 2000, and to retrieve them in batches of 5000:
369

370
```ruby
371
User.find_each(:start => 2000, :batch_size => 5000) do |user|
372 373
  NewsLetter.weekly_deliver(user)
end
374
```
375

376
Another example would be if you wanted multiple workers handling the same processing queue. You could have each worker handle 10000 records by setting the appropriate <tt>:start</tt> option on each worker.
377

378
NOTE: The +:include+ option allows you to name associations that should be loaded alongside with the models.
379

380
#### +find_in_batches+
381

382
The +find_in_batches+ method is similar to +find_each+, since both retrieve batches of records. The difference is that +find_in_batches+ yields _batches_ to the block as an array of models, instead of individually. The following example will yield to the supplied block an array of up to 1000 invoices at a time, with the final block containing any remaining invoices:
383

384
```ruby
385
# Give add_invoices an array of 1000 invoices at a time
386 387 388
Invoice.find_in_batches(:include => :invoice_lines) do |invoices|
  export.add_invoices(invoices)
end
389
```
390

391
NOTE: The +:include+ option allows you to name associations that should be loaded alongside with the models.
392

393
##### Options for +find_in_batches+
394 395 396

The +find_in_batches+ method accepts the same +:batch_size+ and +:start+ options as +find_each+, as well as most of the options allowed by the regular +find+ method, except for +:order+ and +:limit+, which are reserved for internal use by +find_in_batches+.

397 398
Conditions
----------
399

400
The +where+ method allows you to specify conditions to limit the records returned, representing the +WHERE+-part of the SQL statement. Conditions can either be specified as a string, array, or hash.
401

402
### Pure String Conditions
403

404
If you'd like to add conditions to your find, you could just specify them in there, just like +Client.where("orders_count = '2'")+. This will find all clients where the +orders_count+ field's value is 2.
405

406
WARNING: Building your own conditions as pure strings can leave you vulnerable to SQL injection exploits. For example, +Client.where("first_name LIKE '%#{params[:first_name]}%'")+ is not safe. See the next section for the preferred way to handle conditions using an array.
407

408
### Array Conditions
409

410
Now what if that number could vary, say as an argument from somewhere? The find would then take the form:
P
Pratik Naik 已提交
411

412
```ruby
P
Pratik Naik 已提交
413
Client.where("orders_count = ?", params[:orders])
414
```
P
Pratik Naik 已提交
415

416
Active Record will go through the first element in the conditions value and any additional elements will replace the question marks +(?)+ in the first element.
P
Pratik Naik 已提交
417

418
If you want to specify multiple conditions:
P
Pratik Naik 已提交
419

420
```ruby
P
Pratik Naik 已提交
421
Client.where("orders_count = ? AND locked = ?", params[:orders], false)
422
```
P
Pratik Naik 已提交
423 424

In this example, the first question mark will be replaced with the value in +params[:orders]+ and the second will be replaced with the SQL representation of +false+, which depends on the adapter.
425

426
This code is highly preferable:
427

428
```ruby
P
Pratik Naik 已提交
429
Client.where("orders_count = ?", params[:orders])
430
```
431

432
to this code:
433

434
```ruby
435
Client.where("orders_count = #{params[:orders]}")
436
```
437

438
because of argument safety. Putting the variable directly into the conditions string will pass the variable to the database *as-is*. This means that it will be an unescaped variable directly from a user who may have malicious intent. If you do this, you put your entire database at risk because once a user finds out he or she can exploit your database they can do just about anything to it. Never ever put your arguments directly inside the conditions string.
439

440
TIP: For more information on the dangers of SQL injection, see the "Ruby on Rails Security Guide":security.html#sql-injection.
441

442
#### Placeholder Conditions
P
Pratik Naik 已提交
443

444
Similar to the +(?)+ replacement style of params, you can also specify keys/values hash in your array conditions:
P
Pratik Naik 已提交
445

446
```ruby
447 448
Client.where("created_at >= :start_date AND created_at <= :end_date",
  {:start_date => params[:start_date], :end_date => params[:end_date]})
449
```
P
Pratik Naik 已提交
450 451 452

This makes for clearer readability if you have a large number of variable conditions.

453
### Hash Conditions
454

455
Active Record also allows you to pass in hash conditions which can increase the readability of your conditions syntax. With hash conditions, you pass in a hash with keys of the fields you want conditionalised and the values of how you want to conditionalise them:
456

P
Pratik Naik 已提交
457 458
NOTE: Only equality, range and subset checking are possible with Hash conditions.

459
#### Equality Conditions
P
Pratik Naik 已提交
460

461
```ruby
462
Client.where(:locked => true)
463
```
464

465
The field name can also be a string:
466

467
```ruby
468
Client.where('locked' => true)
469
```
470

471 472 473 474 475 476 477
In the case of a belongs_to relationship, an association key can be used to specify the model if an ActiveRecord object is used as the value. This method works with polymorphic relationships as well.

<ruby>
Post.where(:author => author)
Author.joins(:posts).where(:posts => {:author => author})
</ruby>

V
Vijay Dev 已提交
478
NOTE: The values cannot be symbols. For example, you cannot do +Client.where(:status => :active)+.
479

480
#### Range Conditions
P
Pratik Naik 已提交
481

482
```ruby
483
Client.where(:created_at => (Time.now.midnight - 1.day)..Time.now.midnight)
484
```
485

486
This will find all clients created yesterday by using a +BETWEEN+ SQL statement:
487

488
```sql
489
SELECT * FROM clients WHERE (clients.created_at BETWEEN '2008-12-21 00:00:00' AND '2008-12-22 00:00:00')
490
```
491

492
This demonstrates a shorter syntax for the examples in "Array Conditions":#array-conditions
493

494
#### Subset Conditions
P
Pratik Naik 已提交
495 496

If you want to find records using the +IN+ expression you can pass an array to the conditions hash:
497

498
```ruby
499
Client.where(:orders_count => [1,3,5])
500
```
501

P
Pratik Naik 已提交
502
This code will generate SQL like this:
503

504
```sql
505
SELECT * FROM clients WHERE (clients.orders_count IN (1,3,5))
506
```
507

508 509
Ordering
--------
510

511
To retrieve records from the database in a specific order, you can use the +order+ method.
512 513 514

For example, if you're getting a set of records and want to order them in ascending order by the +created_at+ field in your table:

515
```ruby
516
Client.order("created_at")
517
```
518 519 520

You could specify +ASC+ or +DESC+ as well:

521
```ruby
522
Client.order("created_at DESC")
523
# OR
524
Client.order("created_at ASC")
525
```
526 527 528

Or ordering by multiple fields:

529
```ruby
530
Client.order("orders_count ASC, created_at DESC")
531 532
# OR
Client.order("orders_count ASC", "created_at DESC")
533
```
534

535 536
If you want to call +order+ multiple times e.g. in different context, new order will prepend previous one

537
```ruby
538 539
Client.order("orders_count ASC").order("created_at DESC")
# SELECT * FROM clients ORDER BY created_at DESC, orders_count ASC
540
```
541

542 543
Selecting Specific Fields
-------------------------
544 545

By default, <tt>Model.find</tt> selects all the fields from the result set using +select *+.
546

547
To select only a subset of fields from the result set, you can specify the subset via the +select+ method.
548

549
NOTE: If the +select+ method is used, all the returning objects will be "read only":#readonly-objects.
550 551 552 553 554

<br />

For example, to select only +viewable_by+ and +locked+ columns:

555
```ruby
556
Client.select("viewable_by, locked")
557
```
558 559 560

The SQL query used by this find call will be somewhat like:

561
```sql
562
SELECT viewable_by, locked FROM clients
563
```
564 565 566

Be careful because this also means you're initializing a model object with only the fields that you've selected. If you attempt to access a field that is not in the initialized record you'll receive:

567
```shell
568
ActiveModel::MissingAttributeError: missing attribute: <attribute>
569
```
570

K
kommissar 已提交
571
Where +&lt;attribute&gt;+ is the attribute you asked for. The +id+ method will not raise the +ActiveRecord::MissingAttributeError+, so just be careful when working with associations because they need the +id+ method to function properly.
572

573
If you would like to only grab a single record per unique value in a certain field, you can use +uniq+:
574

575
```ruby
576
Client.select(:name).uniq
577
```
578 579 580

This would generate SQL like:

581
```sql
582
SELECT DISTINCT name FROM clients
583
```
584 585 586

You can also remove the uniqueness constraint:

587
```ruby
588 589 590 591 592
query = Client.select(:name).uniq
# => Returns unique names

query.uniq(false)
# => Returns all names, even if there are duplicates
593
```
594

595 596
Limit and Offset
----------------
597

598
To apply +LIMIT+ to the SQL fired by the +Model.find+, you can specify the +LIMIT+ using +limit+ and +offset+ methods on the relation.
599

600
You can use +limit+ to specify the number of records to be retrieved, and use +offset+ to specify the number of records to skip before starting to return the records. For example
601

602
```ruby
603
Client.limit(5)
604
```
605

606
will return a maximum of 5 clients and because it specifies no offset it will return the first 5 in the table. The SQL it executes looks like this:
607

608
```sql
609
SELECT * FROM clients LIMIT 5
610
```
611

612
Adding +offset+ to that
613

614
```ruby
615
Client.limit(5).offset(30)
616
```
617

618
will return instead a maximum of 5 clients beginning with the 31st. The SQL looks like:
619

620
```sql
A
Akira Matsuda 已提交
621
SELECT * FROM clients LIMIT 5 OFFSET 30
622
```
623

624 625
Group
-----
626

627
To apply a +GROUP BY+ clause to the SQL fired by the finder, you can specify the +group+ method on the find.
628 629

For example, if you want to find a collection of the dates orders were created on:
630

631
```ruby
A
Akira Matsuda 已提交
632
Order.select("date(created_at) as ordered_date, sum(price) as total_price").group("date(created_at)")
633
```
634 635 636 637 638

And this will give you a single +Order+ object for each date where there are orders in the database.

The SQL that would be executed would be something like this:

639
```sql
640 641
SELECT date(created_at) as ordered_date, sum(price) as total_price
FROM orders
B
Bertrand Chardon 已提交
642
GROUP BY date(created_at)
643
```
644

645 646
Having
------
647

648
SQL uses the +HAVING+ clause to specify conditions on the +GROUP BY+ fields. You can add the +HAVING+ clause to the SQL fired by the +Model.find+ by adding the +:having+ option to the find.
649

650
For example:
651

652
```ruby
A
Akira Matsuda 已提交
653
Order.select("date(created_at) as ordered_date, sum(price) as total_price").group("date(created_at)").having("sum(price) > ?", 100)
654
```
655

656 657
The SQL that would be executed would be something like this:

658
```sql
659 660 661
SELECT date(created_at) as ordered_date, sum(price) as total_price
FROM orders
GROUP BY date(created_at)
B
Bertrand Chardon 已提交
662
HAVING sum(price) > 100
663
```
664

A
Akira Matsuda 已提交
665
This will return single order objects for each day, but only those that are ordered more than $100 in a day.
666

667 668
Overriding Conditions
---------------------
669

670
### +except+
671

672
You can specify certain conditions to be excepted by using the +except+ method. For example:
673

674
```ruby
675
Post.where('id > 10').limit(20).order('id asc').except(:order)
676
```
677 678 679

The SQL that would be executed:

680
```sql
681
SELECT * FROM posts WHERE id > 10 LIMIT 20
682
```
683

684
### +only+
685

686
You can also override conditions using the +only+ method. For example:
687

688
```ruby
689
Post.where('id > 10').limit(20).order('id desc').only(:order, :where)
690
```
691 692 693

The SQL that would be executed:

694
```sql
695
SELECT * FROM posts WHERE id > 10 ORDER BY id DESC
696
```
697

698
### +reorder+
699 700 701

The +reorder+ method overrides the default scope order. For example:

702
```ruby
703 704 705 706 707 708 709
class Post < ActiveRecord::Base
  ..
  ..
  has_many :comments, :order => 'posted_at DESC'
end

Post.find(10).comments.reorder('name')
710
```
711 712 713

The SQL that would be executed:

714
```sql
715
SELECT * FROM posts WHERE id = 10 ORDER BY name
716
```
717 718 719

In case the +reorder+ clause is not used, the SQL executed would be:

720
```sql
721
SELECT * FROM posts WHERE id = 10 ORDER BY posted_at DESC
722
```
723

724
### +reverse_order+
725 726 727

The +reverse_order+ method reverses the ordering clause if specified.

728
```ruby
729
Client.where("orders_count > 10").order(:name).reverse_order
730
```
731 732

The SQL that would be executed:
733

734
```sql
735
SELECT * FROM clients WHERE orders_count > 10 ORDER BY name DESC
736
```
737 738 739

If no ordering clause is specified in the query, the +reverse_order+ orders by the primary key in reverse order.

740
```ruby
741
Client.where("orders_count > 10").reverse_order
742
```
743 744

The SQL that would be executed:
745

746
```sql
747
SELECT * FROM clients WHERE orders_count > 10 ORDER BY clients.id DESC
748
```
749 750 751

This method accepts *no* arguments.

752 753
Null Relation
-------------
754 755 756

The +none+ method returns a chainable relation with no records. Any subsequent conditions chained to the returned relation will continue generating empty relations. This is useful in scenarios where you need a chainable response to a method or a scope that could return zero results.

757
```ruby
758
Post.none # returns an empty Relation and fires no queries.
759
```
760

761
```ruby
762 763 764 765 766 767 768 769 770 771 772 773 774
# The visible_posts method below is expected to return a Relation.
@posts = current_user.visible_posts.where(:name => params[:name])

def visible_posts
  case role
  when 'Country Manager'
    Post.where(:country => country)
  when 'Reviewer'
    Post.published
  when 'Bad User'
    Post.none # => returning [] or nil breaks the caller code in this case
  end
end
775
```
776

777 778
Readonly Objects
----------------
779

780
Active Record provides +readonly+ method on a relation to explicitly disallow modification of any of the returned objects. Any attempt to alter a readonly record will not succeed, raising an +ActiveRecord::ReadOnlyRecord+ exception.
781

782
```ruby
P
Pratik Naik 已提交
783 784
client = Client.readonly.first
client.visits += 1
785
client.save
786
```
787

R
Ryan Bigg 已提交
788
As +client+ is explicitly set to be a readonly object, the above code will raise an +ActiveRecord::ReadOnlyRecord+ exception when calling +client.save+ with an updated value of _visits_.
P
Pratik Naik 已提交
789

790 791
Locking Records for Update
--------------------------
792

793 794 795
Locking is helpful for preventing race conditions when updating records in the database and ensuring atomic updates.

Active Record provides two locking mechanisms:
796 797 798 799

* Optimistic Locking
* Pessimistic Locking

800
### Optimistic Locking
801

802
Optimistic locking allows multiple users to access the same record for edits, and assumes a minimum of conflicts with the data. It does this by checking whether another process has made changes to a record since it was opened. An +ActiveRecord::StaleObjectError+ exception is thrown if that has occurred and the update is ignored.
803 804 805

<strong>Optimistic locking column</strong>

806
In order to use optimistic locking, the table needs to have a column called +lock_version+ of type integer. Each time the record is updated, Active Record increments the +lock_version+ column. If an update request is made with a lower value in the +lock_version+ field than is currently in the +lock_version+ column in the database, the update request will fail with an +ActiveRecord::StaleObjectError+. Example:
807

808
```ruby
809 810 811
c1 = Client.find(1)
c2 = Client.find(1)

812
c1.first_name = "Michael"
813 814 815
c1.save

c2.name = "should fail"
M
Michael Hutchinson 已提交
816
c2.save # Raises an ActiveRecord::StaleObjectError
817
```
818 819 820 821

You're then responsible for dealing with the conflict by rescuing the exception and either rolling back, merging, or otherwise apply the business logic needed to resolve the conflict.

This behavior can be turned off by setting <tt>ActiveRecord::Base.lock_optimistically = false</tt>.
822

823
To override the name of the +lock_version+ column, +ActiveRecord::Base+ provides a class attribute called +locking_column+:
824

825
```ruby
826
class Client < ActiveRecord::Base
827
  self.locking_column = :lock_client_column
828
end
829
```
830

831
### Pessimistic Locking
832

P
Pratik Naik 已提交
833
Pessimistic locking uses a locking mechanism provided by the underlying database. Using +lock+ when building a relation obtains an exclusive lock on the selected rows. Relations using +lock+ are usually wrapped inside a transaction for preventing deadlock conditions.
834 835

For example:
836

837
```ruby
838
Item.transaction do
P
Pratik Naik 已提交
839
  i = Item.lock.first
840 841
  i.name = 'Jones'
  i.save
842
end
843
```
844

845 846
The above session produces the following SQL for a MySQL backend:

847
```sql
848 849 850 851
SQL (0.2ms)   BEGIN
Item Load (0.3ms)   SELECT * FROM `items` LIMIT 1 FOR UPDATE
Item Update (0.4ms)   UPDATE `items` SET `updated_at` = '2009-02-07 18:05:56', `name` = 'Jones' WHERE `id` = 1
SQL (0.8ms)   COMMIT
852
```
853

P
Pratik Naik 已提交
854
You can also pass raw SQL to the +lock+ method for allowing different types of locks. For example, MySQL has an expression called +LOCK IN SHARE MODE+ where you can lock a record but still allow other queries to read it. To specify this expression just pass it in as the lock option:
855

856
```ruby
857
Item.transaction do
P
Pratik Naik 已提交
858
  i = Item.lock("LOCK IN SHARE MODE").find(1)
859 860
  i.increment!(:views)
end
861
```
862

863 864
If you already have an instance of your model, you can start a transaction and acquire the lock in one go using the following code:

865
```ruby
866 867 868 869 870 871
item = Item.first
item.with_lock do
  # This block is called within a transaction,
  # item is already locked.
  item.increment!(:views)
end
872
```
873

874 875
Joining Tables
--------------
876

P
Pratik Naik 已提交
877
Active Record provides a finder method called +joins+ for specifying +JOIN+ clauses on the resulting SQL. There are multiple ways to use the +joins+ method.
878

879
### Using a String SQL Fragment
880

P
Pratik Naik 已提交
881
You can just supply the raw SQL specifying the +JOIN+ clause to +joins+:
882

883
```ruby
P
Pratik Naik 已提交
884
Client.joins('LEFT OUTER JOIN addresses ON addresses.client_id = clients.id')
885
```
886 887 888

This will result in the following SQL:

889
```sql
P
Pratik Naik 已提交
890
SELECT clients.* FROM clients LEFT OUTER JOIN addresses ON addresses.client_id = clients.id
891
```
892

893
### Using Array/Hash of Named Associations
894

895
WARNING: This method only works with +INNER JOIN+.
896

P
Pratik Naik 已提交
897
Active Record lets you use the names of the "associations":association_basics.html defined on the model as a shortcut for specifying +JOIN+ clause for those associations when using the +joins+ method.
898 899 900

For example, consider the following +Category+, +Post+, +Comments+ and +Guest+ models:

901
```ruby
902 903 904 905 906 907 908 909 910 911
class Category < ActiveRecord::Base
  has_many :posts
end

class Post < ActiveRecord::Base
  belongs_to :category
  has_many :comments
  has_many :tags
end

912
class Comment < ActiveRecord::Base
913 914 915 916 917 918 919
  belongs_to :post
  has_one :guest
end

class Guest < ActiveRecord::Base
  belongs_to :comment
end
920 921 922 923

class Tag < ActiveRecord::Base
  belongs_to :post
end
924
```
925 926 927

Now all of the following will produce the expected join queries using +INNER JOIN+:

928
#### Joining a Single Association
929

930
```ruby
931
Category.joins(:posts)
932
```
933 934 935

This produces:

936
```sql
937 938
SELECT categories.* FROM categories
  INNER JOIN posts ON posts.category_id = categories.id
939
```
940

941
Or, in English: "return a Category object for all categories with posts". Note that you will see duplicate categories if more than one post has the same category. If you want unique categories, you can use Category.joins(:posts).select("distinct(categories.id)").
942

943
#### Joining Multiple Associations
944

945
```ruby
946
Post.joins(:category, :comments)
947
```
948

949
This produces:
950

951
```sql
952
SELECT posts.* FROM posts
953 954
  INNER JOIN categories ON posts.category_id = categories.id
  INNER JOIN comments ON comments.post_id = posts.id
955
```
956

957 958
Or, in English: "return all posts that have a category and at least one comment". Note again that posts with multiple comments will show up multiple times.

959
#### Joining Nested Associations (Single Level)
960

961
```ruby
962
Post.joins(:comments => :guest)
963
```
964

965 966
This produces:

967
```sql
968 969 970
SELECT posts.* FROM posts
  INNER JOIN comments ON comments.post_id = posts.id
  INNER JOIN guests ON guests.comment_id = comments.id
971
```
972 973 974

Or, in English: "return all posts that have a comment made by a guest."

975
#### Joining Nested Associations (Multiple Level)
976

977
```ruby
978
Category.joins(:posts => [{:comments => :guest}, :tags])
979
```
980

981 982
This produces:

983
```sql
984 985 986 987 988
SELECT categories.* FROM categories
  INNER JOIN posts ON posts.category_id = categories.id
  INNER JOIN comments ON comments.post_id = posts.id
  INNER JOIN guests ON guests.comment_id = comments.id
  INNER JOIN tags ON tags.post_id = posts.id
989
```
990

991
### Specifying Conditions on the Joined Tables
992

993
You can specify conditions on the joined tables using the regular "Array":#array-conditions and "String":#pure-string-conditions conditions. "Hash conditions":#hash-conditions provides a special syntax for specifying conditions for the joined tables:
994

995
```ruby
996
time_range = (Time.now.midnight - 1.day)..Time.now.midnight
997
Client.joins(:orders).where('orders.created_at' => time_range)
998
```
999

1000
An alternative and cleaner syntax is to nest the hash conditions:
1001

1002
```ruby
1003
time_range = (Time.now.midnight - 1.day)..Time.now.midnight
1004
Client.joins(:orders).where(:orders => {:created_at => time_range})
1005
```
1006 1007 1008

This will find all clients who have orders that were created yesterday, again using a +BETWEEN+ SQL expression.

1009 1010
Eager Loading Associations
--------------------------
1011 1012

Eager loading is the mechanism for loading the associated records of the objects returned by +Model.find+ using as few queries as possible.
1013

1014 1015 1016 1017
<strong>N <plus> 1 queries problem</strong>

Consider the following code, which finds 10 clients and prints their postcodes:

1018
```ruby
V
Vijay Dev 已提交
1019
clients = Client.limit(10)
1020 1021 1022 1023

clients.each do |client|
  puts client.address.postcode
end
1024
```
1025 1026 1027 1028 1029

This code looks fine at the first sight. But the problem lies within the total number of queries executed. The above code executes 1 ( to find 10 clients ) <plus> 10 ( one per each client to load the address ) = <strong>11</strong> queries in total.

<strong>Solution to N <plus> 1 queries problem</strong>

1030
Active Record lets you specify in advance all the associations that are going to be loaded. This is possible by specifying the +includes+ method of the +Model.find+ call. With +includes+, Active Record ensures that all of the specified associations are loaded using the minimum possible number of queries.
1031

1032
Revisiting the above case, we could rewrite +Client.limit(10)+ to use eager load addresses:
1033

1034
```ruby
J
James Miller 已提交
1035
clients = Client.includes(:address).limit(10)
1036 1037 1038 1039

clients.each do |client|
  puts client.address.postcode
end
1040
```
1041 1042

The above code will execute just <strong>2</strong> queries, as opposed to <strong>11</strong> queries in the previous case:
1043

1044
```sql
1045
SELECT * FROM clients LIMIT 10
1046 1047
SELECT addresses.* FROM addresses
  WHERE (addresses.client_id IN (1,2,3,4,5,6,7,8,9,10))
1048
```
1049

1050
### Eager Loading Multiple Associations
1051

1052
Active Record lets you eager load any number of associations with a single +Model.find+ call by using an array, hash, or a nested hash of array/hash with the +includes+ method.
1053

1054
#### Array of Multiple Associations
1055

1056
```ruby
J
James Miller 已提交
1057
Post.includes(:category, :comments)
1058
```
1059

1060 1061
This loads all the posts and the associated category and comments for each post.

1062
#### Nested Associations Hash
1063

1064
```ruby
X
Xavier Noria 已提交
1065
Category.includes(:posts => [{:comments => :guest}, :tags]).find(1)
1066
```
1067

1068
This will find the category with id 1 and eager load all of the associated posts, the associated posts' tags and comments, and every comment's guest association.
1069

1070
### Specifying Conditions on Eager Loaded Associations
1071

1072
Even though Active Record lets you specify conditions on the eager loaded associations just like +joins+, the recommended way is to use "joins":#joining-tables instead.
1073

1074 1075
However if you must do this, you may use +where+ as you would normally.

1076
```ruby
C
Chun-wei Kuo 已提交
1077
Post.includes(:comments).where("comments.visible" => true)
1078
```
1079 1080 1081

This would generate a query which contains a +LEFT OUTER JOIN+ whereas the +joins+ method would generate one using the +INNER JOIN+ function instead.

1082
```ruby
V
Vijay Dev 已提交
1083
  SELECT "posts"."id" AS t0_r0, ... "comments"."updated_at" AS t1_r5 FROM "posts" LEFT OUTER JOIN "comments" ON "comments"."post_id" = "posts"."id" WHERE (comments.visible = 1)
1084
```
1085

1086 1087 1088
If there was no +where+ condition, this would generate the normal set of two queries.

If, in the case of this +includes+ query, there were no comments for any posts, all the posts would still be loaded. By using +joins+ (an INNER JOIN), the join conditions *must* match, otherwise no records will be returned.
1089

1090 1091
Scopes
------
1092

1093
Scoping allows you to specify commonly-used queries which can be referenced as method calls on the association objects or models. With these scopes, you can use every method previously covered such as +where+, +joins+ and +includes+. All scope methods will return an +ActiveRecord::Relation+ object which will allow for further methods (such as other scopes) to be called on it.
1094

1095
To define a simple scope, we use the +scope+ method inside the class, passing the query that we'd like run when this scope is called:
1096

1097
```ruby
R
Ryan Bigg 已提交
1098
class Post < ActiveRecord::Base
1099
  scope :published, -> { where(published: true) }
R
Ryan Bigg 已提交
1100
end
1101
```
1102

1103
This is exactly the same as defining a class method, and which you use is a matter of personal preference:
1104

1105
```ruby
R
Ryan Bigg 已提交
1106
class Post < ActiveRecord::Base
1107 1108 1109
  def self.published
    where(published: true)
  end
R
Ryan Bigg 已提交
1110
end
1111
```
1112 1113 1114

Scopes are also chainable within scopes:

1115
```ruby
R
Ryan Bigg 已提交
1116
class Post < ActiveRecord::Base
1117
  scope :published,               -> { where(:published => true) }
1118
  scope :published_and_commented, -> { published.where("comments_count > 0") }
R
Ryan Bigg 已提交
1119
end
1120
```
1121 1122 1123

To call this +published+ scope we can call it on either the class:

1124
```ruby
1125
Post.published # => [published posts]
1126
```
1127 1128 1129

Or on an association consisting of +Post+ objects:

1130
```ruby
R
Ryan Bigg 已提交
1131
category = Category.first
1132
category.posts.published # => [published posts belonging to this category]
1133
```
1134

1135
### Passing in arguments
1136

J
Jon Leighton 已提交
1137
Your scope can take arguments:
1138

1139
```ruby
1140
class Post < ActiveRecord::Base
1141
  scope :created_before, ->(time) { where("created_at < ?", time) }
1142
end
1143
```
1144 1145 1146

This may then be called using this:

1147
```ruby
1148
Post.created_before(Time.zone.now)
1149
```
1150 1151 1152

However, this is just duplicating the functionality that would be provided to you by a class method.

1153
```ruby
1154
class Post < ActiveRecord::Base
1155
  def self.created_before(time)
1156 1157 1158
    where("created_at < ?", time)
  end
end
1159
```
1160

1161 1162
Using a class method is the preferred way to accept arguments for scopes. These methods will still be accessible on the association objects:

1163
```ruby
1164
category.posts.created_before(time)
1165
```
1166

1167
### Applying a default scope
1168

1169 1170
If we wish for a scope to be applied across all queries to the model we can use the
+default_scope+ method within the model itself.
1171

1172
```ruby
V
Vijay Dev 已提交
1173
class Client < ActiveRecord::Base
1174
  default_scope { where("removed_at IS NULL") }
V
Vijay Dev 已提交
1175
end
1176
```
1177

1178 1179
When queries are executed on this model, the SQL query will now look something like
this:
1180

1181
```sql
V
Vijay Dev 已提交
1182
SELECT * FROM clients WHERE removed_at IS NULL
1183
```
1184

1185 1186
If you need to do more complex things with a default scope, you can alternatively
define it as a class method:
1187

1188
```ruby
1189 1190
class Client < ActiveRecord::Base
  def self.default_scope
1191
    # Should return an ActiveRecord::Relation.
1192 1193
  end
end
1194
```
1195

1196
### Removing all scoping
1197

1198 1199 1200
If we wish to remove scoping for any reason we can use the +unscoped+ method. This is
especially useful if a +default_scope+ is specified in the model and should not be
applied for this particular query.
1201

1202
```ruby
V
Vijay Dev 已提交
1203
Client.unscoped.all
1204
```
1205 1206 1207

This method removes all scoping and will do a normal query on the table.

V
Vijay Dev 已提交
1208
Note that chaining +unscoped+ with a +scope+ does not work. In these cases, it is
1209 1210
recommended that you use the block form of +unscoped+:

1211
```ruby
1212 1213 1214
Client.unscoped {
  Client.created_before(Time.zome.now)
}
1215
```
1216

1217 1218
Dynamic Finders
---------------
1219

1220
For every field (also known as an attribute) you define in your table, Active Record provides a finder method. If you have a field called +first_name+ on your +Client+ model for example, you get +find_by_first_name+ and +find_all_by_first_name+ for free from Active Record. If you have a +locked+ field on the +Client+ model, you also get +find_by_locked+ and +find_all_by_locked+ methods.
1221

1222
You can also use +find_last_by_*+ methods which will find the last record matching your argument.
1223

K
kommissar 已提交
1224
You can specify an exclamation point (<tt>!</tt>) on the end of the dynamic finders to get them to raise an +ActiveRecord::RecordNotFound+ error if they do not return any records, like +Client.find_by_name!("Ryan")+
1225

1226
If you want to find both by name and locked, you can chain these finders together by simply typing "+and+" between the fields. For example, +Client.find_by_first_name_and_locked("Ryan", true)+.
1227

1228
WARNING: Up to and including Rails 3.1, when the number of arguments passed to a dynamic finder method is lesser than the number of fields, say <tt>Client.find_by_name_and_locked("Ryan")</tt>, the behavior is to pass +nil+ as the missing argument. This is *unintentional* and this behavior will be changed in Rails 3.2 to throw an +ArgumentError+.
1229

1230 1231
Find or build a new object
--------------------------
1232 1233 1234

It's common that you need to find a record or create it if it doesn't exist. You can do that with the +first_or_create+ and +first_or_create!+ methods.

1235
### +first_or_create+
1236 1237 1238 1239 1240

The +first_or_create+ method checks whether +first+ returns +nil+ or not. If it does return +nil+, then +create+ is called. This is very powerful when coupled with the +where+ method. Let's see an example.

Suppose you want to find a client named 'Andy', and if there's none, create one and additionally set his +locked+ attribute to false. You can do so by running:

1241
```ruby
1242
Client.where(:first_name => 'Andy').first_or_create(:locked => false)
1243
# => #<Client id: 1, first_name: "Andy", orders_count: 0, locked: false, created_at: "2011-08-30 06:09:27", updated_at: "2011-08-30 06:09:27">
1244
```
1245 1246

The SQL generated by this method looks like this:
1247

1248
```sql
1249
SELECT * FROM clients WHERE (clients.first_name = 'Andy') LIMIT 1
1250
BEGIN
1251
INSERT INTO clients (created_at, first_name, locked, orders_count, updated_at) VALUES ('2011-08-30 05:22:57', 'Andy', 0, NULL, '2011-08-30 05:22:57')
1252
COMMIT
1253
```
1254

1255
+first_or_create+ returns either the record that already exists or the new record. In our case, we didn't already have a client named Andy so the record is created and returned.
1256 1257 1258 1259 1260

The new record might not be saved to the database; that depends on whether validations passed or not (just like +create+).

It's also worth noting that +first_or_create+ takes into account the arguments of the +where+ method. In the example above we didn't explicitly pass a +:first_name => 'Andy'+ argument to +first_or_create+. However, that was used when creating the new record because it was already passed before to the +where+ method.

1261 1262
You can do the same with the +find_or_create_by+ method:

1263
```ruby
1264
Client.find_or_create_by_first_name(:first_name => "Andy", :locked => false)
1265
```
1266 1267

This method still works, but it's encouraged to use +first_or_create+ because it's more explicit on which arguments are used to _find_ the record and which are used to _create_, resulting in less confusion overall.
1268

1269
### +first_or_create!+
1270 1271 1272

You can also use +first_or_create!+ to raise an exception if the new record is invalid. Validations are not covered on this guide, but let's assume for a moment that you temporarily add

1273
```ruby
1274
validates :orders_count, :presence => true
1275
```
1276 1277 1278

to your +Client+ model. If you try to create a new +Client+ without passing an +orders_count+, the record will be invalid and an exception will be raised:

1279
```ruby
1280
Client.where(:first_name => 'Andy').first_or_create!(:locked => false)
1281
# => ActiveRecord::RecordInvalid: Validation failed: Orders count can't be blank
1282
```
1283

1284 1285
As with +first_or_create+ there is a +find_or_create_by!+ method but the +first_or_create!+ method is preferred for clarity.

1286
### +first_or_initialize+
1287

1288
The +first_or_initialize+ method will work just like +first_or_create+ but it will not call +create+ but +new+. This means that a new model instance will be created in memory but won't be saved to the database. Continuing with the +first_or_create+ example, we now want the client named 'Nick':
1289

1290
```ruby
1291
nick = Client.where(:first_name => 'Nick').first_or_initialize(:locked => false)
1292
# => <Client id: nil, first_name: "Nick", orders_count: 0, locked: false, created_at: "2011-08-30 06:09:27", updated_at: "2011-08-30 06:09:27">
1293 1294

nick.persisted?
1295
# => false
1296 1297

nick.new_record?
1298
# => true
1299
```
1300 1301 1302

Because the object is not yet stored in the database, the SQL generated looks like this:

1303
```sql
1304
SELECT * FROM clients WHERE (clients.first_name = 'Nick') LIMIT 1
1305
```
1306 1307

When you want to save it to the database, just call +save+:
1308

1309
```ruby
1310
nick.save
1311
# => true
1312
```
1313

1314 1315
Finding by SQL
--------------
1316

L
logylaps 已提交
1317
If you'd like to use your own SQL to find records in a table you can use +find_by_sql+. The +find_by_sql+ method will return an array of objects even if the underlying query returns just a single record. For example you could run this query:
1318

1319
```ruby
1320 1321
Client.find_by_sql("SELECT * FROM clients
  INNER JOIN orders ON clients.id = orders.client_id
P
Pratik Naik 已提交
1322
  ORDER clients.created_at desc")
1323
```
1324 1325 1326

+find_by_sql+ provides you with a simple way of making custom calls to the database and retrieving instantiated objects.

1327 1328
+select_all+
------------
1329

P
Pratik Naik 已提交
1330
<tt>find_by_sql</tt> has a close relative called +connection#select_all+. +select_all+ will retrieve objects from the database using custom SQL just like +find_by_sql+ but will not instantiate them. Instead, you will get an array of hashes where each hash indicates a record.
1331

1332
```ruby
1333
Client.connection.select_all("SELECT * FROM clients WHERE id = '1'")
1334
```
1335

1336 1337
+pluck+
-------
1338

1339
<tt>pluck</tt> can be used to query a single or multiple columns from the underlying table of a model. It accepts a list of column names as argument and returns an array of values of the specified columns with the corresponding data type.
1340

1341
```ruby
V
Vijay Dev 已提交
1342 1343
Client.where(:active => true).pluck(:id)
# SELECT id FROM clients WHERE active = 1
1344
# => [1, 2, 3]
V
Vijay Dev 已提交
1345 1346 1347

Client.uniq.pluck(:role)
# SELECT DISTINCT role FROM clients
1348 1349 1350 1351 1352
# => ['admin', 'member', 'guest']

Client.pluck(:id, :name)
# SELECT clients.id, clients.name FROM clients
# => [[1, 'David'], [2, 'Jeremy'], [3, 'Jose']]
1353
```
V
Vijay Dev 已提交
1354 1355 1356

+pluck+ makes it possible to replace code like

1357
```ruby
V
Vijay Dev 已提交
1358
Client.select(:id).map { |c| c.id }
1359 1360
# or
Client.select(:id).map { |c| [c.id, c.name] }
1361
```
V
Vijay Dev 已提交
1362 1363 1364

with

1365
```ruby
V
Vijay Dev 已提交
1366
Client.pluck(:id)
1367 1368
# or
Client.pluck(:id, :name)
1369
```
1370

1371 1372
+ids+
-----
1373 1374 1375

+ids+ can be used to pluck all the IDs for the relation using the table's primary key.

1376
```ruby
1377 1378
Person.ids
# SELECT id FROM people
1379
```
1380

1381
```ruby
1382 1383 1384 1385 1386 1387
class Person < ActiveRecord::Base
  self.primary_key = "person_id"
end

Person.ids
# SELECT person_id FROM people
1388
```
1389

1390 1391
Existence of Objects
--------------------
1392

P
Pratik Naik 已提交
1393
If you simply want to check for the existence of the object there's a method called +exists?+. This method will query the database using the same query as +find+, but instead of returning an object or collection of objects it will return either +true+ or +false+.
1394

1395
```ruby
1396
Client.exists?(1)
1397
```
1398 1399 1400

The +exists?+ method also takes multiple ids, but the catch is that it will return true if any one of those records exists.

1401
```ruby
1402 1403 1404
Client.exists?(1,2,3)
# or
Client.exists?([1,2,3])
1405
```
1406

P
Pratik Naik 已提交
1407
It's even possible to use +exists?+ without any arguments on a model or a relation.
1408

1409
```ruby
P
Pratik Naik 已提交
1410
Client.where(:first_name => 'Ryan').exists?
1411
```
1412

P
Pratik Naik 已提交
1413
The above returns +true+ if there is at least one client with the +first_name+ 'Ryan' and +false+ otherwise.
P
Pratik Naik 已提交
1414

1415
```ruby
P
Pratik Naik 已提交
1416
Client.exists?
1417
```
P
Pratik Naik 已提交
1418 1419 1420

The above returns +false+ if the +clients+ table is empty and +true+ otherwise.

1421 1422
You can also use +any?+ and +many?+ to check for existence on a model or relation.

1423
```ruby
1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438
# via a model
Post.any?
Post.many?

# via a named scope
Post.recent.any?
Post.recent.many?

# via a relation
Post.where(:published => true).any?
Post.where(:published => true).many?

# via an association
Post.first.categories.any?
Post.first.categories.many?
1439
```
1440

1441 1442
Calculations
------------
1443 1444 1445

This section uses count as an example method in this preamble, but the options described apply to all sub-sections.

P
Pratik Naik 已提交
1446
All calculation methods work directly on a model:
1447

1448
```ruby
P
Pratik Naik 已提交
1449 1450
Client.count
# SELECT count(*) AS count_all FROM clients
1451
```
1452

M
Matt Duncan 已提交
1453
Or on a relation:
1454

1455
```ruby
P
Pratik Naik 已提交
1456 1457
Client.where(:first_name => 'Ryan').count
# SELECT count(*) AS count_all FROM clients WHERE (first_name = 'Ryan')
1458
```
1459

P
Pratik Naik 已提交
1460
You can also use various finder methods on a relation for performing complex calculations:
1461

1462
```ruby
P
Pratik Naik 已提交
1463
Client.includes("orders").where(:first_name => 'Ryan', :orders => {:status => 'received'}).count
1464
```
1465 1466 1467

Which will execute:

1468
```sql
1469 1470 1471
SELECT count(DISTINCT clients.id) AS count_all FROM clients
  LEFT OUTER JOIN orders ON orders.client_id = client.id WHERE
  (clients.first_name = 'Ryan' AND orders.status = 'received')
1472
```
1473

1474
### Count
1475 1476 1477 1478 1479

If you want to see how many records are in your model's table you could call +Client.count+ and that will return the number. If you want to be more specific and find all the clients with their age present in the database you can use +Client.count(:age)+.

For options, please see the parent section, "Calculations":#calculations.

1480
### Average
1481 1482 1483

If you want to see the average of a certain number in one of your tables you can call the +average+ method on the class that relates to the table. This method call will look something like this:

1484
```ruby
1485
Client.average("orders_count")
1486
```
1487 1488 1489 1490 1491

This will return a number (possibly a floating point number such as 3.14159265) representing the average value in the field.

For options, please see the parent section, "Calculations":#calculations.

1492
### Minimum
1493 1494 1495

If you want to find the minimum value of a field in your table you can call the +minimum+ method on the class that relates to the table. This method call will look something like this:

1496
```ruby
1497
Client.minimum("age")
1498
```
1499 1500 1501

For options, please see the parent section, "Calculations":#calculations.

1502
### Maximum
1503 1504 1505

If you want to find the maximum value of a field in your table you can call the +maximum+ method on the class that relates to the table. This method call will look something like this:

1506
```ruby
1507
Client.maximum("age")
1508
```
1509 1510 1511

For options, please see the parent section, "Calculations":#calculations.

1512
### Sum
1513 1514 1515

If you want to find the sum of a field for all records in your table you can call the +sum+ method on the class that relates to the table. This method call will look something like this:

1516
```ruby
1517
Client.sum("orders_count")
1518
```
1519

1520
For options, please see the parent section, "Calculations":#calculations.
X
Xavier Noria 已提交
1521

1522 1523
Running EXPLAIN
---------------
X
Xavier Noria 已提交
1524 1525 1526

You can run EXPLAIN on the queries triggered by relations. For example,

1527
```ruby
X
Xavier Noria 已提交
1528
User.where(:id => 1).joins(:posts).explain
1529
```
X
Xavier Noria 已提交
1530 1531 1532

may yield

1533
```
1534
EXPLAIN for: SELECT `users`.* FROM `users` INNER JOIN `posts` ON `posts`.`user_id` = `users`.`id` WHERE `users`.`id` = 1
V
Vijay Dev 已提交
1535
<plus>----<plus>-------------<plus>-------<plus>-------<plus>---------------<plus>---------<plus>---------<plus>-------<plus>------<plus>-------------<plus>
X
Xavier Noria 已提交
1536
| id | select_type | table | type  | possible_keys | key     | key_len | ref   | rows | Extra       |
V
Vijay Dev 已提交
1537
<plus>----<plus>-------------<plus>-------<plus>-------<plus>---------------<plus>---------<plus>---------<plus>-------<plus>------<plus>-------------<plus>
X
Xavier Noria 已提交
1538 1539
|  1 | SIMPLE      | users | const | PRIMARY       | PRIMARY | 4       | const |    1 |             |
|  1 | SIMPLE      | posts | ALL   | NULL          | NULL    | NULL    | NULL  |    1 | Using where |
V
Vijay Dev 已提交
1540
<plus>----<plus>-------------<plus>-------<plus>-------<plus>---------------<plus>---------<plus>---------<plus>-------<plus>------<plus>-------------<plus>
X
Xavier Noria 已提交
1541
2 rows in set (0.00 sec)
1542
```
X
Xavier Noria 已提交
1543 1544 1545 1546

under MySQL.

Active Record performs a pretty printing that emulates the one of the database
V
Vijay Dev 已提交
1547
shells. So, the same query running with the PostgreSQL adapter would yield instead
X
Xavier Noria 已提交
1548

1549
```
1550
EXPLAIN for: SELECT "users".* FROM "users" INNER JOIN "posts" ON "posts"."user_id" = "users"."id" WHERE "users"."id" = 1
X
Xavier Noria 已提交
1551 1552 1553 1554 1555 1556 1557 1558 1559
                                  QUERY PLAN
------------------------------------------------------------------------------
 Nested Loop Left Join  (cost=0.00..37.24 rows=8 width=0)
   Join Filter: (posts.user_id = users.id)
   ->  Index Scan using users_pkey on users  (cost=0.00..8.27 rows=1 width=4)
         Index Cond: (id = 1)
   ->  Seq Scan on posts  (cost=0.00..28.88 rows=8 width=4)
         Filter: (posts.user_id = 1)
(6 rows)
1560
```
X
Xavier Noria 已提交
1561 1562 1563 1564 1565

Eager loading may trigger more than one query under the hood, and some queries
may need the results of previous ones. Because of that, +explain+ actually
executes the query, and then asks for the query plans. For example,

1566
```ruby
X
Xavier Noria 已提交
1567
User.where(:id => 1).includes(:posts).explain
1568
```
X
Xavier Noria 已提交
1569 1570 1571

yields

1572
```
1573
EXPLAIN for: SELECT `users`.* FROM `users`  WHERE `users`.`id` = 1
1574
<plus>----<plus>-------------<plus>-------<plus>-------<plus>---------------<plus>---------<plus>---------<plus>-------<plus>------<plus>-------<plus>
X
Xavier Noria 已提交
1575
| id | select_type | table | type  | possible_keys | key     | key_len | ref   | rows | Extra |
1576
<plus>----<plus>-------------<plus>-------<plus>-------<plus>---------------<plus>---------<plus>---------<plus>-------<plus>------<plus>-------<plus>
X
Xavier Noria 已提交
1577
|  1 | SIMPLE      | users | const | PRIMARY       | PRIMARY | 4       | const |    1 |       |
1578
<plus>----<plus>-------------<plus>-------<plus>-------<plus>---------------<plus>---------<plus>---------<plus>-------<plus>------<plus>-------<plus>
X
Xavier Noria 已提交
1579
1 row in set (0.00 sec)
1580 1581

EXPLAIN for: SELECT `posts`.* FROM `posts`  WHERE `posts`.`user_id` IN (1)
1582
<plus>----<plus>-------------<plus>-------<plus>------<plus>---------------<plus>------<plus>---------<plus>------<plus>------<plus>-------------<plus>
X
Xavier Noria 已提交
1583
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |
1584
<plus>----<plus>-------------<plus>-------<plus>------<plus>---------------<plus>------<plus>---------<plus>------<plus>------<plus>-------------<plus>
X
Xavier Noria 已提交
1585
|  1 | SIMPLE      | posts | ALL  | NULL          | NULL | NULL    | NULL |    1 | Using where |
1586
<plus>----<plus>-------------<plus>-------<plus>------<plus>---------------<plus>------<plus>---------<plus>------<plus>------<plus>-------------<plus>
X
Xavier Noria 已提交
1587
1 row in set (0.00 sec)
1588
```
X
Xavier Noria 已提交
1589 1590

under MySQL.
1591

1592
### Automatic EXPLAIN
1593 1594 1595 1596

Active Record is able to run EXPLAIN automatically on slow queries and log its
output. This feature is controlled by the configuration parameter

1597
```ruby
1598
config.active_record.auto_explain_threshold_in_seconds
1599
```
1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611

If set to a number, any query exceeding those many seconds will have its EXPLAIN
automatically triggered and logged. In the case of relations, the threshold is
compared to the total time needed to fetch records. So, a relation is seen as a
unit of work, no matter whether the implementation of eager loading involves
several queries under the hood.

A threshold of +nil+ disables automatic EXPLAINs.

The default threshold in development mode is 0.5 seconds, and +nil+ in test and
production modes.

1612 1613 1614
INFO. Automatic EXPLAIN gets disabled if Active Record has no logger, regardless
of the value of the threshold.

1615
#### Disabling Automatic EXPLAIN
1616

1617
Automatic EXPLAIN can be selectively silenced with +ActiveRecord::Base.silence_auto_explain+:
1618

1619
```ruby
1620
ActiveRecord::Base.silence_auto_explain do
1621
  # no automatic EXPLAIN is triggered here
1622
end
1623
```
1624

V
Vijay Dev 已提交
1625
That may be useful for queries you know are slow but fine, like a heavyweight
1626 1627 1628 1629 1630
report of an admin interface.

As its name suggests, +silence_auto_explain+ only silences automatic EXPLAINs.
Explicit calls to +ActiveRecord::Relation#explain+ run.

1631
### Interpreting EXPLAIN
1632 1633 1634 1635 1636 1637 1638 1639 1640

Interpretation of the output of EXPLAIN is beyond the scope of this guide. The
following pointers may be helpful:

* SQLite3: "EXPLAIN QUERY PLAN":http://www.sqlite.org/eqp.html

* MySQL: "EXPLAIN Output Format":http://dev.mysql.com/doc/refman/5.6/en/explain-output.html

* PostgreSQL: "Using EXPLAIN":http://www.postgresql.org/docs/current/static/using-explain.html