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

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 已提交
11
* Run EXPLAIN on relations
12 13 14

endprologue.

15
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.
16 17 18

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

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

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

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

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

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

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

X
Xavier Noria 已提交
49
h3. Retrieving Objects from the Database
50

51
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.
52 53

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

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

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

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

X
Xavier Noria 已提交
87
h4. Retrieving a Single Object
88

89
Active Record provides five different ways of retrieving a single object.
90

X
Xavier Noria 已提交
91
h5. Using a Primary Key
92

93
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:
94

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

101
The SQL equivalent of the above is:
102

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

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

109 110
h5. +take+

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

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

The SQL equivalent of the above is:

120
```sql
121
SELECT * FROM clients LIMIT 1
122
```
123

124 125 126
<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.
127

X
Xavier Noria 已提交
128
h5. +first+
129

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

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

137
The SQL equivalent of the above is:
138

139
```sql
140
SELECT * FROM clients ORDER BY clients.id ASC LIMIT 1
141
```
142

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

X
Xavier Noria 已提交
145
h5. +last+
146

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

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

154
The SQL equivalent of the above is:
155

156
```sql
157
SELECT * FROM clients ORDER BY clients.id DESC LIMIT 1
158
```
159

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

162 163 164 165
h5. +find_by+

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

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

Client.find_by first_name: 'Jon'
# => nil
172
```
173 174 175

It is equivalent to writing:

176
```ruby
177
Client.where(first_name: 'Lifo').take
178
```
179

180 181 182 183
h5(#take_1). +take!+

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

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

The SQL equivalent of the above is:

191
```sql
192
SELECT * FROM clients LIMIT 1
193
```
194

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

197
h5(#first_1). +first!+
198

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

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

206
The SQL equivalent of the above is:
207

208
```sql
209
SELECT * FROM clients ORDER BY clients.id ASC LIMIT 1
210
```
211

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

214
h5(#last_1). +last!+
215

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

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

223
The SQL equivalent of the above is:
224

225
```sql
226
SELECT * FROM clients ORDER BY clients.id DESC LIMIT 1
227
```
228

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

231 232
h5(#find_by_1). +find_by!+

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

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

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

It is equivalent to writing:

245
```ruby
246
Client.where(first_name: 'Lifo').take!
247
```
248

X
Xavier Noria 已提交
249
h4. Retrieving Multiple Objects
250

X
Xavier Noria 已提交
251
h5. Using Multiple Primary Keys
252

253
<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:
254

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

261
The SQL equivalent of the above is:
262

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

267
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.
268

269
h5(#take-n-objects). take
270 271 272

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

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

The SQL equivalent of the above is:

281
```sql
282
SELECT * FROM clients LIMIT 2
283
```
284

285
h5(#first-n-objects). first
286 287 288

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

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

The SQL equivalent of the above is:

297
```sql
298
SELECT * FROM clients LIMIT 2
299
```
300

301
h5(#last-n-objects). last
302 303 304

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

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

The SQL equivalent of the above is:

313
```sql
314
SELECT * FROM clients ORDER By id DESC LIMIT 2
315
```
316

X
Xavier Noria 已提交
317
h4. Retrieving Multiple Objects in Batches
318

319
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.
320

321
This may appear straightforward:
322

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

330
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.
331

332
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.
333 334

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.
335 336 337

h5. +find_each+

338
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:
339

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

346 347 348
h6. Options for +find_each+

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+.
349

350
Two additional options, +:batch_size+ and +:start+, are available as well.
351

352 353 354
*+: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:
355

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

362
*+:start+*
363

364
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.
365

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

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

374
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.
375

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

h5. +find_in_batches+

380
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:
381

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

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

391 392 393 394
h6. Options for +find_in_batches+

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+.

395 396
h3. Conditions

397
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.
398

X
Xavier Noria 已提交
399
h4. Pure String Conditions
400

401
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.
402

403
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.
404

X
Xavier Noria 已提交
405
h4. Array Conditions
406

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

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

413
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 已提交
414

415
If you want to specify multiple conditions:
P
Pratik Naik 已提交
416

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

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.
422

423
This code is highly preferable:
424

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

429
to this code:
430

431
```ruby
432
Client.where("orders_count = #{params[:orders]}")
433
```
434

435
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.
436

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

X
Xavier Noria 已提交
439
h5. Placeholder Conditions
P
Pratik Naik 已提交
440

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

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

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

X
Xavier Noria 已提交
450
h4. Hash Conditions
451

452
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:
453

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

X
Xavier Noria 已提交
456
h5. Equality Conditions
P
Pratik Naik 已提交
457

458
```ruby
459
Client.where(:locked => true)
460
```
461

462
The field name can also be a string:
463

464
```ruby
465
Client.where('locked' => true)
466
```
467

468 469 470 471 472 473 474
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 已提交
475
NOTE: The values cannot be symbols. For example, you cannot do +Client.where(:status => :active)+.
476

477
h5(#hash-range_conditions). Range Conditions
P
Pratik Naik 已提交
478

479
```ruby
480
Client.where(:created_at => (Time.now.midnight - 1.day)..Time.now.midnight)
481
```
482

483
This will find all clients created yesterday by using a +BETWEEN+ SQL statement:
484

485
```sql
486
SELECT * FROM clients WHERE (clients.created_at BETWEEN '2008-12-21 00:00:00' AND '2008-12-22 00:00:00')
487
```
488

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

X
Xavier Noria 已提交
491
h5. Subset Conditions
P
Pratik Naik 已提交
492 493

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

495
```ruby
496
Client.where(:orders_count => [1,3,5])
497
```
498

P
Pratik Naik 已提交
499
This code will generate SQL like this:
500

501
```sql
502
SELECT * FROM clients WHERE (clients.orders_count IN (1,3,5))
503
```
504

505
h3(#ordering). Ordering
506

507
To retrieve records from the database in a specific order, you can use the +order+ method.
508 509 510

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:

511
```ruby
512
Client.order("created_at")
513
```
514 515 516

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

517
```ruby
518
Client.order("created_at DESC")
519
# OR
520
Client.order("created_at ASC")
521
```
522 523 524

Or ordering by multiple fields:

525
```ruby
526
Client.order("orders_count ASC, created_at DESC")
527 528
# OR
Client.order("orders_count ASC", "created_at DESC")
529
```
530

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

533
```ruby
534 535
Client.order("orders_count ASC").order("created_at DESC")
# SELECT * FROM clients ORDER BY created_at DESC, orders_count ASC
536
```
537

538
h3. Selecting Specific Fields
539 540

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

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

544
NOTE: If the +select+ method is used, all the returning objects will be "read only":#readonly-objects.
545 546 547 548 549

<br />

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

550
```ruby
551
Client.select("viewable_by, locked")
552
```
553 554 555

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

556
```sql
557
SELECT viewable_by, locked FROM clients
558
```
559 560 561

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:

562
```shell
563
ActiveModel::MissingAttributeError: missing attribute: <attribute>
564
```
565

K
kommissar 已提交
566
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.
567

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

570
```ruby
571
Client.select(:name).uniq
572
```
573 574 575

This would generate SQL like:

576
```sql
577
SELECT DISTINCT name FROM clients
578
```
579 580 581

You can also remove the uniqueness constraint:

582
```ruby
583 584 585 586 587
query = Client.select(:name).uniq
# => Returns unique names

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

590
h3. Limit and Offset
591

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

594
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
595

596
```ruby
597
Client.limit(5)
598
```
599

600
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:
601

602
```sql
603
SELECT * FROM clients LIMIT 5
604
```
605

606
Adding +offset+ to that
607

608
```ruby
609
Client.limit(5).offset(30)
610
```
611

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

614
```sql
A
Akira Matsuda 已提交
615
SELECT * FROM clients LIMIT 5 OFFSET 30
616
```
617

618
h3. Group
619

620
To apply a +GROUP BY+ clause to the SQL fired by the finder, you can specify the +group+ method on the find.
621 622

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

624
```ruby
A
Akira Matsuda 已提交
625
Order.select("date(created_at) as ordered_date, sum(price) as total_price").group("date(created_at)")
626
```
627 628 629 630 631

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:

632
```sql
633 634
SELECT date(created_at) as ordered_date, sum(price) as total_price
FROM orders
B
Bertrand Chardon 已提交
635
GROUP BY date(created_at)
636
```
637

638
h3. Having
639

640
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.
641

642
For example:
643

644
```ruby
A
Akira Matsuda 已提交
645
Order.select("date(created_at) as ordered_date, sum(price) as total_price").group("date(created_at)").having("sum(price) > ?", 100)
646
```
647

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

650
```sql
651 652 653
SELECT date(created_at) as ordered_date, sum(price) as total_price
FROM orders
GROUP BY date(created_at)
B
Bertrand Chardon 已提交
654
HAVING sum(price) > 100
655
```
656

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

659 660
h3. Overriding Conditions

661
h4. +except+
662

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

665
```ruby
666
Post.where('id > 10').limit(20).order('id asc').except(:order)
667
```
668 669 670

The SQL that would be executed:

671
```sql
672
SELECT * FROM posts WHERE id > 10 LIMIT 20
673
```
674

675
h4. +only+
676

677
You can also override conditions using the +only+ method. For example:
678

679
```ruby
680
Post.where('id > 10').limit(20).order('id desc').only(:order, :where)
681
```
682 683 684

The SQL that would be executed:

685
```sql
686
SELECT * FROM posts WHERE id > 10 ORDER BY id DESC
687
```
688

689 690 691 692
h4. +reorder+

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

693
```ruby
694 695 696 697 698 699 700
class Post < ActiveRecord::Base
  ..
  ..
  has_many :comments, :order => 'posted_at DESC'
end

Post.find(10).comments.reorder('name')
701
```
702 703 704

The SQL that would be executed:

705
```sql
706
SELECT * FROM posts WHERE id = 10 ORDER BY name
707
```
708 709 710

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

711
```sql
712
SELECT * FROM posts WHERE id = 10 ORDER BY posted_at DESC
713
```
714

715 716 717 718
h4. +reverse_order+

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

719
```ruby
720
Client.where("orders_count > 10").order(:name).reverse_order
721
```
722 723

The SQL that would be executed:
724

725
```sql
726
SELECT * FROM clients WHERE orders_count > 10 ORDER BY name DESC
727
```
728 729 730

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

731
```ruby
732
Client.where("orders_count > 10").reverse_order
733
```
734 735

The SQL that would be executed:
736

737
```sql
738
SELECT * FROM clients WHERE orders_count > 10 ORDER BY clients.id DESC
739
```
740 741 742

This method accepts *no* arguments.

743 744 745 746
h3. Null Relation

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.

747
```ruby
748
Post.none # returns an empty Relation and fires no queries.
749
```
750

751
```ruby
752 753 754 755 756 757 758 759 760 761 762 763 764
# 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
765
```
766

767
h3. Readonly Objects
768

769
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.
770

771
```ruby
P
Pratik Naik 已提交
772 773
client = Client.readonly.first
client.visits += 1
774
client.save
775
```
776

R
Ryan Bigg 已提交
777
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 已提交
778

779
h3. Locking Records for Update
780

781 782 783
Locking is helpful for preventing race conditions when updating records in the database and ensuring atomic updates.

Active Record provides two locking mechanisms:
784 785 786 787

* Optimistic Locking
* Pessimistic Locking

788
h4. Optimistic Locking
789

790
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.
791 792 793

<strong>Optimistic locking column</strong>

794
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:
795

796
```ruby
797 798 799
c1 = Client.find(1)
c2 = Client.find(1)

800
c1.first_name = "Michael"
801 802 803
c1.save

c2.name = "should fail"
M
Michael Hutchinson 已提交
804
c2.save # Raises an ActiveRecord::StaleObjectError
805
```
806 807 808 809

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>.
810

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

813
```ruby
814
class Client < ActiveRecord::Base
815
  self.locking_column = :lock_client_column
816
end
817
```
818

819
h4. Pessimistic Locking
820

P
Pratik Naik 已提交
821
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.
822 823

For example:
824

825
```ruby
826
Item.transaction do
P
Pratik Naik 已提交
827
  i = Item.lock.first
828 829
  i.name = 'Jones'
  i.save
830
end
831
```
832

833 834
The above session produces the following SQL for a MySQL backend:

835
```sql
836 837 838 839
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
840
```
841

P
Pratik Naik 已提交
842
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:
843

844
```ruby
845
Item.transaction do
P
Pratik Naik 已提交
846
  i = Item.lock("LOCK IN SHARE MODE").find(1)
847 848
  i.increment!(:views)
end
849
```
850

851 852
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:

853
```ruby
854 855 856 857 858 859
item = Item.first
item.with_lock do
  # This block is called within a transaction,
  # item is already locked.
  item.increment!(:views)
end
860
```
861

X
Xavier Noria 已提交
862
h3. Joining Tables
863

P
Pratik Naik 已提交
864
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.
865

X
Xavier Noria 已提交
866
h4. Using a String SQL Fragment
867

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

870
```ruby
P
Pratik Naik 已提交
871
Client.joins('LEFT OUTER JOIN addresses ON addresses.client_id = clients.id')
872
```
873 874 875

This will result in the following SQL:

876
```sql
P
Pratik Naik 已提交
877
SELECT clients.* FROM clients LEFT OUTER JOIN addresses ON addresses.client_id = clients.id
878
```
879

X
Xavier Noria 已提交
880
h4. Using Array/Hash of Named Associations
881

882
WARNING: This method only works with +INNER JOIN+.
883

P
Pratik Naik 已提交
884
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.
885 886 887

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

888
```ruby
889 890 891 892 893 894 895 896 897 898
class Category < ActiveRecord::Base
  has_many :posts
end

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

899
class Comment < ActiveRecord::Base
900 901 902 903 904 905 906
  belongs_to :post
  has_one :guest
end

class Guest < ActiveRecord::Base
  belongs_to :comment
end
907 908 909 910

class Tag < ActiveRecord::Base
  belongs_to :post
end
911
```
912 913 914

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

X
Xavier Noria 已提交
915
h5. Joining a Single Association
916

917
```ruby
918
Category.joins(:posts)
919
```
920 921 922

This produces:

923
```sql
924 925
SELECT categories.* FROM categories
  INNER JOIN posts ON posts.category_id = categories.id
926
```
927

928
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)").
929

X
Xavier Noria 已提交
930
h5. Joining Multiple Associations
931

932
```ruby
933
Post.joins(:category, :comments)
934
```
935

936
This produces:
937

938
```sql
939
SELECT posts.* FROM posts
940 941
  INNER JOIN categories ON posts.category_id = categories.id
  INNER JOIN comments ON comments.post_id = posts.id
942
```
943

944 945
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.

X
Xavier Noria 已提交
946
h5. Joining Nested Associations (Single Level)
947

948
```ruby
949
Post.joins(:comments => :guest)
950
```
951

952 953
This produces:

954
```sql
955 956 957
SELECT posts.* FROM posts
  INNER JOIN comments ON comments.post_id = posts.id
  INNER JOIN guests ON guests.comment_id = comments.id
958
```
959 960 961

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

X
Xavier Noria 已提交
962
h5. Joining Nested Associations (Multiple Level)
963

964
```ruby
965
Category.joins(:posts => [{:comments => :guest}, :tags])
966
```
967

968 969
This produces:

970
```sql
971 972 973 974 975
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
976
```
977

X
Xavier Noria 已提交
978
h4. Specifying Conditions on the Joined Tables
979

980
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:
981

982
```ruby
983
time_range = (Time.now.midnight - 1.day)..Time.now.midnight
984
Client.joins(:orders).where('orders.created_at' => time_range)
985
```
986

987
An alternative and cleaner syntax is to nest the hash conditions:
988

989
```ruby
990
time_range = (Time.now.midnight - 1.day)..Time.now.midnight
991
Client.joins(:orders).where(:orders => {:created_at => time_range})
992
```
993 994 995

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

X
Xavier Noria 已提交
996
h3. Eager Loading Associations
997 998

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

1000 1001 1002 1003
<strong>N <plus> 1 queries problem</strong>

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

1004
```ruby
V
Vijay Dev 已提交
1005
clients = Client.limit(10)
1006 1007 1008 1009

clients.each do |client|
  puts client.address.postcode
end
1010
```
1011 1012 1013 1014 1015

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>

1016
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.
1017

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

1020
```ruby
J
James Miller 已提交
1021
clients = Client.includes(:address).limit(10)
1022 1023 1024 1025

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

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

1030
```sql
1031
SELECT * FROM clients LIMIT 10
1032 1033
SELECT addresses.* FROM addresses
  WHERE (addresses.client_id IN (1,2,3,4,5,6,7,8,9,10))
1034
```
1035

X
Xavier Noria 已提交
1036
h4. Eager Loading Multiple Associations
1037

1038
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.
1039

1040
h5. Array of Multiple Associations
1041

1042
```ruby
J
James Miller 已提交
1043
Post.includes(:category, :comments)
1044
```
1045

1046 1047
This loads all the posts and the associated category and comments for each post.

X
Xavier Noria 已提交
1048
h5. Nested Associations Hash
1049

1050
```ruby
X
Xavier Noria 已提交
1051
Category.includes(:posts => [{:comments => :guest}, :tags]).find(1)
1052
```
1053

1054
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.
1055

X
Xavier Noria 已提交
1056
h4. Specifying Conditions on Eager Loaded Associations
1057

1058
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.
1059

1060 1061
However if you must do this, you may use +where+ as you would normally.

1062
```ruby
C
Chun-wei Kuo 已提交
1063
Post.includes(:comments).where("comments.visible" => true)
1064
```
1065 1066 1067

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

1068
```ruby
V
Vijay Dev 已提交
1069
  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)
1070
```
1071

1072 1073 1074
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.
1075

1076 1077
h3. Scopes

1078
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.
1079

1080
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:
1081

1082
```ruby
R
Ryan Bigg 已提交
1083
class Post < ActiveRecord::Base
1084
  scope :published, -> { where(published: true) }
R
Ryan Bigg 已提交
1085
end
1086
```
1087

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

1090
```ruby
R
Ryan Bigg 已提交
1091
class Post < ActiveRecord::Base
1092 1093 1094
  def self.published
    where(published: true)
  end
R
Ryan Bigg 已提交
1095
end
1096
```
1097 1098 1099

Scopes are also chainable within scopes:

1100
```ruby
R
Ryan Bigg 已提交
1101
class Post < ActiveRecord::Base
1102
  scope :published,               -> { where(:published => true) }
1103
  scope :published_and_commented, -> { published.where("comments_count > 0") }
R
Ryan Bigg 已提交
1104
end
1105
```
1106 1107 1108

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

1109
```ruby
1110
Post.published # => [published posts]
1111
```
1112 1113 1114

Or on an association consisting of +Post+ objects:

1115
```ruby
R
Ryan Bigg 已提交
1116
category = Category.first
1117
category.posts.published # => [published posts belonging to this category]
1118
```
1119

1120 1121
h4. Passing in arguments

J
Jon Leighton 已提交
1122
Your scope can take arguments:
1123

1124
```ruby
1125
class Post < ActiveRecord::Base
1126
  scope :created_before, ->(time) { where("created_at < ?", time) }
1127
end
1128
```
1129 1130 1131

This may then be called using this:

1132
```ruby
1133
Post.created_before(Time.zone.now)
1134
```
1135 1136 1137

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

1138
```ruby
1139
class Post < ActiveRecord::Base
1140
  def self.created_before(time)
1141 1142 1143
    where("created_at < ?", time)
  end
end
1144
```
1145

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

1148
```ruby
1149
category.posts.created_before(time)
1150
```
1151

1152 1153
h4. Applying a default scope

1154 1155
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.
1156

1157
```ruby
V
Vijay Dev 已提交
1158
class Client < ActiveRecord::Base
1159
  default_scope { where("removed_at IS NULL") }
V
Vijay Dev 已提交
1160
end
1161
```
1162

1163 1164
When queries are executed on this model, the SQL query will now look something like
this:
1165

1166
```sql
V
Vijay Dev 已提交
1167
SELECT * FROM clients WHERE removed_at IS NULL
1168
```
1169

1170 1171
If you need to do more complex things with a default scope, you can alternatively
define it as a class method:
1172 1173 1174 1175

<ruby>
class Client < ActiveRecord::Base
  def self.default_scope
1176
    # Should return an ActiveRecord::Relation.
1177 1178 1179 1180
  end
end
</ruby>

1181 1182
h4. Removing all scoping

1183 1184 1185
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.
1186

1187
```ruby
V
Vijay Dev 已提交
1188
Client.unscoped.all
1189
```
1190 1191 1192

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

V
Vijay Dev 已提交
1193
Note that chaining +unscoped+ with a +scope+ does not work. In these cases, it is
1194 1195 1196 1197 1198 1199 1200 1201
recommended that you use the block form of +unscoped+:

<ruby>
Client.unscoped {
  Client.created_before(Time.zome.now)
}
</ruby>

X
Xavier Noria 已提交
1202
h3. Dynamic Finders
1203

1204
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.
1205

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

K
kommissar 已提交
1208
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")+
1209

1210
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)+.
1211

1212
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+.
1213

1214 1215 1216 1217 1218 1219 1220 1221 1222 1223
h3. Find or build a new object

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.

h4. +first_or_create+

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:

1224
```ruby
1225
Client.where(:first_name => 'Andy').first_or_create(:locked => false)
1226
# => #<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">
1227
```
1228 1229

The SQL generated by this method looks like this:
1230

1231
```sql
1232
SELECT * FROM clients WHERE (clients.first_name = 'Andy') LIMIT 1
1233
BEGIN
1234
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')
1235
COMMIT
1236
```
1237

1238
+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.
1239 1240 1241 1242 1243

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.

1244 1245
You can do the same with the +find_or_create_by+ method:

1246
```ruby
1247
Client.find_or_create_by_first_name(:first_name => "Andy", :locked => false)
1248
```
1249 1250

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.
1251

1252
h4(#first_or_create_bang). +first_or_create!+
1253 1254 1255

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

1256
```ruby
1257
validates :orders_count, :presence => true
1258
```
1259 1260 1261

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:

1262
```ruby
1263
Client.where(:first_name => 'Andy').first_or_create!(:locked => false)
1264
# => ActiveRecord::RecordInvalid: Validation failed: Orders count can't be blank
1265
```
1266

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

1269
h4. +first_or_initialize+
1270

1271
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':
1272

1273
```ruby
1274
nick = Client.where(:first_name => 'Nick').first_or_initialize(:locked => false)
1275
# => <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">
1276 1277

nick.persisted?
1278
# => false
1279 1280

nick.new_record?
1281
# => true
1282
```
1283 1284 1285

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

1286
```sql
1287
SELECT * FROM clients WHERE (clients.first_name = 'Nick') LIMIT 1
1288
```
1289 1290

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

1292
```ruby
1293
nick.save
1294
# => true
1295
```
1296

1297
h3. Finding by SQL
1298

L
logylaps 已提交
1299
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:
1300

1301
```ruby
1302 1303
Client.find_by_sql("SELECT * FROM clients
  INNER JOIN orders ON clients.id = orders.client_id
P
Pratik Naik 已提交
1304
  ORDER clients.created_at desc")
1305
```
1306 1307 1308

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

1309
h3. +select_all+
1310

P
Pratik Naik 已提交
1311
<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.
1312

1313
```ruby
1314
Client.connection.select_all("SELECT * FROM clients WHERE id = '1'")
1315
```
1316

1317 1318
h3. +pluck+

1319
<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.
1320

1321
```ruby
V
Vijay Dev 已提交
1322 1323
Client.where(:active => true).pluck(:id)
# SELECT id FROM clients WHERE active = 1
1324
# => [1, 2, 3]
V
Vijay Dev 已提交
1325 1326 1327

Client.uniq.pluck(:role)
# SELECT DISTINCT role FROM clients
1328 1329 1330 1331 1332
# => ['admin', 'member', 'guest']

Client.pluck(:id, :name)
# SELECT clients.id, clients.name FROM clients
# => [[1, 'David'], [2, 'Jeremy'], [3, 'Jose']]
1333
```
V
Vijay Dev 已提交
1334 1335 1336

+pluck+ makes it possible to replace code like

1337
```ruby
V
Vijay Dev 已提交
1338
Client.select(:id).map { |c| c.id }
1339 1340
# or
Client.select(:id).map { |c| [c.id, c.name] }
1341
```
V
Vijay Dev 已提交
1342 1343 1344

with

1345
```ruby
V
Vijay Dev 已提交
1346
Client.pluck(:id)
1347 1348
# or
Client.pluck(:id, :name)
1349
```
1350 1351 1352 1353 1354

h3. +ids+

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

1355
```ruby
1356 1357
Person.ids
# SELECT id FROM people
1358
```
1359

1360
```ruby
1361 1362 1363 1364 1365 1366
class Person < ActiveRecord::Base
  self.primary_key = "person_id"
end

Person.ids
# SELECT person_id FROM people
1367
```
1368

1369 1370
h3. Existence of Objects

P
Pratik Naik 已提交
1371
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+.
1372

1373
```ruby
1374
Client.exists?(1)
1375
```
1376 1377 1378

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

1379
```ruby
1380 1381 1382
Client.exists?(1,2,3)
# or
Client.exists?([1,2,3])
1383
```
1384

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

1387
```ruby
P
Pratik Naik 已提交
1388
Client.where(:first_name => 'Ryan').exists?
1389
```
1390

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

1393
```ruby
P
Pratik Naik 已提交
1394
Client.exists?
1395
```
P
Pratik Naik 已提交
1396 1397 1398

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

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

1401
```ruby
1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416
# 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?
1417
```
1418

1419 1420 1421 1422
h3. Calculations

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

P
Pratik Naik 已提交
1423
All calculation methods work directly on a model:
1424

1425
```ruby
P
Pratik Naik 已提交
1426 1427
Client.count
# SELECT count(*) AS count_all FROM clients
1428
```
1429

M
Matt Duncan 已提交
1430
Or on a relation:
1431

1432
```ruby
P
Pratik Naik 已提交
1433 1434
Client.where(:first_name => 'Ryan').count
# SELECT count(*) AS count_all FROM clients WHERE (first_name = 'Ryan')
1435
```
1436

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

1439
```ruby
P
Pratik Naik 已提交
1440
Client.includes("orders").where(:first_name => 'Ryan', :orders => {:status => 'received'}).count
1441
```
1442 1443 1444

Which will execute:

1445
```sql
1446 1447 1448
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')
1449
```
1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460

h4. Count

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.

h4. Average

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:

1461
```ruby
1462
Client.average("orders_count")
1463
```
1464 1465 1466 1467 1468 1469 1470 1471 1472

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.

h4. Minimum

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:

1473
```ruby
1474
Client.minimum("age")
1475
```
1476 1477 1478 1479 1480 1481 1482

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

h4. Maximum

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:

1483
```ruby
1484
Client.maximum("age")
1485
```
1486 1487 1488 1489 1490 1491 1492

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

h4. Sum

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:

1493
```ruby
1494
Client.sum("orders_count")
1495
```
1496

1497
For options, please see the parent section, "Calculations":#calculations.
X
Xavier Noria 已提交
1498 1499 1500 1501 1502

h3. Running EXPLAIN

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

1503
```ruby
X
Xavier Noria 已提交
1504
User.where(:id => 1).joins(:posts).explain
1505
```
X
Xavier Noria 已提交
1506 1507 1508

may yield

1509
```
1510
EXPLAIN for: SELECT `users`.* FROM `users` INNER JOIN `posts` ON `posts`.`user_id` = `users`.`id` WHERE `users`.`id` = 1
V
Vijay Dev 已提交
1511
<plus>----<plus>-------------<plus>-------<plus>-------<plus>---------------<plus>---------<plus>---------<plus>-------<plus>------<plus>-------------<plus>
X
Xavier Noria 已提交
1512
| id | select_type | table | type  | possible_keys | key     | key_len | ref   | rows | Extra       |
V
Vijay Dev 已提交
1513
<plus>----<plus>-------------<plus>-------<plus>-------<plus>---------------<plus>---------<plus>---------<plus>-------<plus>------<plus>-------------<plus>
X
Xavier Noria 已提交
1514 1515
|  1 | SIMPLE      | users | const | PRIMARY       | PRIMARY | 4       | const |    1 |             |
|  1 | SIMPLE      | posts | ALL   | NULL          | NULL    | NULL    | NULL  |    1 | Using where |
V
Vijay Dev 已提交
1516
<plus>----<plus>-------------<plus>-------<plus>-------<plus>---------------<plus>---------<plus>---------<plus>-------<plus>------<plus>-------------<plus>
X
Xavier Noria 已提交
1517
2 rows in set (0.00 sec)
1518
```
X
Xavier Noria 已提交
1519 1520 1521 1522

under MySQL.

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

1525
```
1526
EXPLAIN for: SELECT "users".* FROM "users" INNER JOIN "posts" ON "posts"."user_id" = "users"."id" WHERE "users"."id" = 1
X
Xavier Noria 已提交
1527 1528 1529 1530 1531 1532 1533 1534 1535
                                  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)
1536
```
X
Xavier Noria 已提交
1537 1538 1539 1540 1541

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,

1542
```ruby
X
Xavier Noria 已提交
1543
User.where(:id => 1).includes(:posts).explain
1544
```
X
Xavier Noria 已提交
1545 1546 1547

yields

1548
```
1549
EXPLAIN for: SELECT `users`.* FROM `users`  WHERE `users`.`id` = 1
1550
<plus>----<plus>-------------<plus>-------<plus>-------<plus>---------------<plus>---------<plus>---------<plus>-------<plus>------<plus>-------<plus>
X
Xavier Noria 已提交
1551
| id | select_type | table | type  | possible_keys | key     | key_len | ref   | rows | Extra |
1552
<plus>----<plus>-------------<plus>-------<plus>-------<plus>---------------<plus>---------<plus>---------<plus>-------<plus>------<plus>-------<plus>
X
Xavier Noria 已提交
1553
|  1 | SIMPLE      | users | const | PRIMARY       | PRIMARY | 4       | const |    1 |       |
1554
<plus>----<plus>-------------<plus>-------<plus>-------<plus>---------------<plus>---------<plus>---------<plus>-------<plus>------<plus>-------<plus>
X
Xavier Noria 已提交
1555
1 row in set (0.00 sec)
1556 1557

EXPLAIN for: SELECT `posts`.* FROM `posts`  WHERE `posts`.`user_id` IN (1)
1558
<plus>----<plus>-------------<plus>-------<plus>------<plus>---------------<plus>------<plus>---------<plus>------<plus>------<plus>-------------<plus>
X
Xavier Noria 已提交
1559
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |
1560
<plus>----<plus>-------------<plus>-------<plus>------<plus>---------------<plus>------<plus>---------<plus>------<plus>------<plus>-------------<plus>
X
Xavier Noria 已提交
1561
|  1 | SIMPLE      | posts | ALL  | NULL          | NULL | NULL    | NULL |    1 | Using where |
1562
<plus>----<plus>-------------<plus>-------<plus>------<plus>---------------<plus>------<plus>---------<plus>------<plus>------<plus>-------------<plus>
X
Xavier Noria 已提交
1563
1 row in set (0.00 sec)
1564
```
X
Xavier Noria 已提交
1565 1566

under MySQL.
1567

1568 1569 1570 1571 1572
h4. Automatic EXPLAIN

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

1573
```ruby
1574
config.active_record.auto_explain_threshold_in_seconds
1575
```
1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587

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.

1588 1589 1590
INFO. Automatic EXPLAIN gets disabled if Active Record has no logger, regardless
of the value of the threshold.

1591 1592
h5. Disabling Automatic EXPLAIN

1593
Automatic EXPLAIN can be selectively silenced with +ActiveRecord::Base.silence_auto_explain+:
1594

1595
```ruby
1596
ActiveRecord::Base.silence_auto_explain do
1597
  # no automatic EXPLAIN is triggered here
1598
end
1599
```
1600

V
Vijay Dev 已提交
1601
That may be useful for queries you know are slow but fine, like a heavyweight
1602 1603 1604 1605 1606
report of an admin interface.

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

1607 1608 1609 1610 1611 1612 1613 1614 1615 1616
h4. Interpreting EXPLAIN

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