rails 4.1.6 → 4.2.11
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +12 -10
- data/guides/CHANGELOG.md +64 -17
- data/guides/Rakefile +21 -6
- data/guides/assets/images/getting_started/article_with_comments.png +0 -0
- data/guides/assets/javascripts/guides.js +6 -0
- data/guides/assets/stylesheets/main.css +4 -1
- data/guides/bug_report_templates/action_controller_gem.rb +3 -3
- data/guides/bug_report_templates/action_controller_master.rb +3 -2
- data/guides/bug_report_templates/active_record_gem.rb +1 -1
- data/guides/bug_report_templates/generic_gem.rb +15 -0
- data/guides/bug_report_templates/generic_master.rb +26 -0
- data/guides/rails_guides/helpers.rb +1 -1
- data/guides/rails_guides/levenshtein.rb +27 -21
- data/guides/rails_guides/markdown/renderer.rb +1 -1
- data/guides/rails_guides/markdown.rb +11 -7
- data/guides/rails_guides.rb +2 -2
- data/guides/source/2_2_release_notes.md +1 -1
- data/guides/source/2_3_release_notes.md +4 -4
- data/guides/source/3_0_release_notes.md +8 -8
- data/guides/source/3_1_release_notes.md +6 -3
- data/guides/source/3_2_release_notes.md +6 -3
- data/guides/source/4_0_release_notes.md +6 -3
- data/guides/source/4_1_release_notes.md +9 -10
- data/guides/source/4_2_release_notes.md +877 -0
- data/guides/source/_license.html.erb +1 -1
- data/guides/source/_welcome.html.erb +6 -8
- data/guides/source/action_controller_overview.md +25 -8
- data/guides/source/action_mailer_basics.md +97 -29
- data/guides/source/action_view_overview.md +142 -191
- data/guides/source/active_job_basics.md +339 -0
- data/guides/source/active_model_basics.md +371 -17
- data/guides/source/active_record_basics.md +25 -24
- data/guides/source/active_record_callbacks.md +12 -9
- data/guides/source/{migrations.md → active_record_migrations.md} +95 -220
- data/guides/source/active_record_postgresql.md +433 -0
- data/guides/source/active_record_querying.md +264 -268
- data/guides/source/active_record_validations.md +23 -13
- data/guides/source/active_support_core_extensions.md +115 -123
- data/guides/source/active_support_instrumentation.md +10 -18
- data/guides/source/api_documentation_guidelines.md +63 -17
- data/guides/source/asset_pipeline.md +259 -120
- data/guides/source/association_basics.md +96 -80
- data/guides/source/autoloading_and_reloading_constants.md +1311 -0
- data/guides/source/caching_with_rails.md +32 -7
- data/guides/source/command_line.md +52 -30
- data/guides/source/configuring.md +161 -33
- data/guides/source/contributing_to_ruby_on_rails.md +198 -114
- data/guides/source/credits.html.erb +2 -2
- data/guides/source/debugging_rails_applications.md +440 -286
- data/guides/source/development_dependencies_install.md +47 -36
- data/guides/source/documents.yaml +19 -7
- data/guides/source/engines.md +217 -196
- data/guides/source/form_helpers.md +79 -56
- data/guides/source/generators.md +24 -11
- data/guides/source/getting_started.md +359 -219
- data/guides/source/i18n.md +110 -66
- data/guides/source/index.html.erb +1 -0
- data/guides/source/initialization.md +109 -62
- data/guides/source/layout.html.erb +5 -11
- data/guides/source/layouts_and_rendering.md +26 -26
- data/guides/source/maintenance_policy.md +6 -3
- data/guides/source/nested_model_forms.md +7 -4
- data/guides/source/plugins.md +27 -27
- data/guides/source/rails_application_templates.md +21 -3
- data/guides/source/rails_on_rack.md +8 -5
- data/guides/source/routing.md +113 -73
- data/guides/source/ruby_on_rails_guides_guidelines.md +11 -12
- data/guides/source/security.md +40 -34
- data/guides/source/testing.md +199 -119
- data/guides/source/upgrading_ruby_on_rails.md +289 -31
- data/guides/source/working_with_javascript_in_rails.md +19 -17
- data/guides/w3c_validator.rb +2 -0
- metadata +42 -95
- data/guides/code/getting_started/Gemfile +0 -40
- data/guides/code/getting_started/Gemfile.lock +0 -125
- data/guides/code/getting_started/README.rdoc +0 -28
- data/guides/code/getting_started/Rakefile +0 -6
- data/guides/code/getting_started/app/assets/javascripts/application.js +0 -15
- data/guides/code/getting_started/app/assets/javascripts/comments.js.coffee +0 -3
- data/guides/code/getting_started/app/assets/javascripts/posts.js.coffee +0 -3
- data/guides/code/getting_started/app/assets/javascripts/welcome.js.coffee +0 -3
- data/guides/code/getting_started/app/assets/stylesheets/application.css +0 -13
- data/guides/code/getting_started/app/assets/stylesheets/comments.css.scss +0 -3
- data/guides/code/getting_started/app/assets/stylesheets/posts.css.scss +0 -3
- data/guides/code/getting_started/app/assets/stylesheets/welcome.css.scss +0 -3
- data/guides/code/getting_started/app/controllers/application_controller.rb +0 -5
- data/guides/code/getting_started/app/controllers/comments_controller.rb +0 -23
- data/guides/code/getting_started/app/controllers/posts_controller.rb +0 -53
- data/guides/code/getting_started/app/controllers/welcome_controller.rb +0 -4
- data/guides/code/getting_started/app/helpers/application_helper.rb +0 -2
- data/guides/code/getting_started/app/helpers/comments_helper.rb +0 -2
- data/guides/code/getting_started/app/helpers/posts_helper.rb +0 -2
- data/guides/code/getting_started/app/helpers/welcome_helper.rb +0 -2
- data/guides/code/getting_started/app/models/comment.rb +0 -3
- data/guides/code/getting_started/app/models/post.rb +0 -7
- data/guides/code/getting_started/app/views/comments/_comment.html.erb +0 -15
- data/guides/code/getting_started/app/views/comments/_form.html.erb +0 -13
- data/guides/code/getting_started/app/views/layouts/application.html.erb +0 -14
- data/guides/code/getting_started/app/views/posts/_form.html.erb +0 -27
- data/guides/code/getting_started/app/views/posts/edit.html.erb +0 -5
- data/guides/code/getting_started/app/views/posts/index.html.erb +0 -21
- data/guides/code/getting_started/app/views/posts/new.html.erb +0 -5
- data/guides/code/getting_started/app/views/posts/show.html.erb +0 -18
- data/guides/code/getting_started/app/views/welcome/index.html.erb +0 -4
- data/guides/code/getting_started/bin/bundle +0 -4
- data/guides/code/getting_started/bin/rails +0 -4
- data/guides/code/getting_started/bin/rake +0 -4
- data/guides/code/getting_started/config/application.rb +0 -18
- data/guides/code/getting_started/config/boot.rb +0 -4
- data/guides/code/getting_started/config/database.yml +0 -25
- data/guides/code/getting_started/config/environment.rb +0 -5
- data/guides/code/getting_started/config/environments/development.rb +0 -30
- data/guides/code/getting_started/config/environments/production.rb +0 -80
- data/guides/code/getting_started/config/environments/test.rb +0 -36
- data/guides/code/getting_started/config/initializers/backtrace_silencers.rb +0 -7
- data/guides/code/getting_started/config/initializers/filter_parameter_logging.rb +0 -4
- data/guides/code/getting_started/config/initializers/inflections.rb +0 -16
- data/guides/code/getting_started/config/initializers/locale.rb +0 -9
- data/guides/code/getting_started/config/initializers/mime_types.rb +0 -5
- data/guides/code/getting_started/config/initializers/secret_token.rb +0 -12
- data/guides/code/getting_started/config/initializers/session_store.rb +0 -3
- data/guides/code/getting_started/config/initializers/wrap_parameters.rb +0 -14
- data/guides/code/getting_started/config/locales/en.yml +0 -23
- data/guides/code/getting_started/config/routes.rb +0 -7
- data/guides/code/getting_started/config.ru +0 -4
- data/guides/code/getting_started/db/migrate/20130122042648_create_posts.rb +0 -10
- data/guides/code/getting_started/db/migrate/20130122045842_create_comments.rb +0 -11
- data/guides/code/getting_started/db/schema.rb +0 -33
- data/guides/code/getting_started/db/seeds.rb +0 -7
- data/guides/code/getting_started/public/404.html +0 -60
- data/guides/code/getting_started/public/422.html +0 -60
- data/guides/code/getting_started/public/500.html +0 -59
- data/guides/code/getting_started/public/favicon.ico +0 -0
- data/guides/code/getting_started/public/robots.txt +0 -5
- data/guides/code/getting_started/test/controllers/comments_controller_test.rb +0 -7
- data/guides/code/getting_started/test/controllers/posts_controller_test.rb +0 -7
- data/guides/code/getting_started/test/controllers/welcome_controller_test.rb +0 -9
- data/guides/code/getting_started/test/fixtures/comments.yml +0 -11
- data/guides/code/getting_started/test/fixtures/posts.yml +0 -9
- data/guides/code/getting_started/test/helpers/comments_helper_test.rb +0 -4
- data/guides/code/getting_started/test/helpers/posts_helper_test.rb +0 -4
- data/guides/code/getting_started/test/helpers/welcome_helper_test.rb +0 -4
- data/guides/code/getting_started/test/models/comment_test.rb +0 -7
- data/guides/code/getting_started/test/models/post_test.rb +0 -7
- data/guides/code/getting_started/test/test_helper.rb +0 -12
@@ -93,9 +93,9 @@ The primary operation of `Model.find(options)` can be summarized as:
|
|
93
93
|
|
94
94
|
Active Record provides several different ways of retrieving a single object.
|
95
95
|
|
96
|
-
####
|
96
|
+
#### `find`
|
97
97
|
|
98
|
-
Using `
|
98
|
+
Using the `find` method, you can retrieve the object corresponding to the specified _primary key_ that matches any supplied options. For example:
|
99
99
|
|
100
100
|
```ruby
|
101
101
|
# Find the client with primary key (id) 10.
|
@@ -109,119 +109,103 @@ The SQL equivalent of the above is:
|
|
109
109
|
SELECT * FROM clients WHERE (clients.id = 10) LIMIT 1
|
110
110
|
```
|
111
111
|
|
112
|
-
`
|
112
|
+
The `find` method will raise an `ActiveRecord::RecordNotFound` exception if no matching record is found.
|
113
113
|
|
114
|
-
|
115
|
-
|
116
|
-
`Model.take` retrieves a record without any implicit ordering. For example:
|
114
|
+
You can also use this method to query for multiple objects. Call the `find` method and pass in an array of primary keys. The return will be an array containing all of the matching records for the supplied _primary keys_. For example:
|
117
115
|
|
118
116
|
```ruby
|
119
|
-
|
120
|
-
|
117
|
+
# Find the clients with primary keys 1 and 10.
|
118
|
+
client = Client.find([1, 10]) # Or even Client.find(1, 10)
|
119
|
+
# => [#<Client id: 1, first_name: "Lifo">, #<Client id: 10, first_name: "Ryan">]
|
121
120
|
```
|
122
121
|
|
123
122
|
The SQL equivalent of the above is:
|
124
123
|
|
125
124
|
```sql
|
126
|
-
SELECT * FROM clients
|
125
|
+
SELECT * FROM clients WHERE (clients.id IN (1,10))
|
127
126
|
```
|
128
127
|
|
129
|
-
`
|
130
|
-
|
131
|
-
TIP: The retrieved record may vary depending on the database engine.
|
128
|
+
WARNING: The `find` method will raise an `ActiveRecord::RecordNotFound` exception unless a matching record is found for **all** of the supplied primary keys.
|
132
129
|
|
133
|
-
#### `
|
130
|
+
#### `take`
|
134
131
|
|
135
|
-
`
|
132
|
+
The `take` method retrieves a record without any implicit ordering. For example:
|
136
133
|
|
137
134
|
```ruby
|
138
|
-
client = Client.
|
135
|
+
client = Client.take
|
139
136
|
# => #<Client id: 1, first_name: "Lifo">
|
140
137
|
```
|
141
138
|
|
142
139
|
The SQL equivalent of the above is:
|
143
140
|
|
144
141
|
```sql
|
145
|
-
SELECT * FROM clients
|
142
|
+
SELECT * FROM clients LIMIT 1
|
146
143
|
```
|
147
144
|
|
148
|
-
`
|
145
|
+
The `take` method returns `nil` if no record is found and no exception will be raised.
|
149
146
|
|
150
|
-
|
151
|
-
|
152
|
-
`Model.last` finds the last record ordered by the primary key. For example:
|
147
|
+
You can pass in a numerical argument to the `take` method to return up to that number of results. For example
|
153
148
|
|
154
149
|
```ruby
|
155
|
-
client = Client.
|
156
|
-
# =>
|
150
|
+
client = Client.take(2)
|
151
|
+
# => [
|
152
|
+
#<Client id: 1, first_name: "Lifo">,
|
153
|
+
#<Client id: 220, first_name: "Sara">
|
154
|
+
]
|
157
155
|
```
|
158
156
|
|
159
157
|
The SQL equivalent of the above is:
|
160
158
|
|
161
159
|
```sql
|
162
|
-
SELECT * FROM clients
|
163
|
-
```
|
164
|
-
|
165
|
-
`Model.last` returns `nil` if no matching record is found and no exception will be raised.
|
166
|
-
|
167
|
-
#### `find_by`
|
168
|
-
|
169
|
-
`Model.find_by` finds the first record matching some conditions. For example:
|
170
|
-
|
171
|
-
```ruby
|
172
|
-
Client.find_by first_name: 'Lifo'
|
173
|
-
# => #<Client id: 1, first_name: "Lifo">
|
174
|
-
|
175
|
-
Client.find_by first_name: 'Jon'
|
176
|
-
# => nil
|
160
|
+
SELECT * FROM clients LIMIT 2
|
177
161
|
```
|
178
162
|
|
179
|
-
|
163
|
+
The `take!` method behaves exactly like `take`, except that it will raise `ActiveRecord::RecordNotFound` if no matching record is found.
|
180
164
|
|
181
|
-
|
182
|
-
Client.where(first_name: 'Lifo').take
|
183
|
-
```
|
165
|
+
TIP: The retrieved record may vary depending on the database engine.
|
184
166
|
|
185
|
-
#### `
|
167
|
+
#### `first`
|
186
168
|
|
187
|
-
`
|
169
|
+
The `first` method finds the first record ordered by the primary key. For example:
|
188
170
|
|
189
171
|
```ruby
|
190
|
-
client = Client.
|
172
|
+
client = Client.first
|
191
173
|
# => #<Client id: 1, first_name: "Lifo">
|
192
174
|
```
|
193
175
|
|
194
176
|
The SQL equivalent of the above is:
|
195
177
|
|
196
178
|
```sql
|
197
|
-
SELECT * FROM clients LIMIT 1
|
179
|
+
SELECT * FROM clients ORDER BY clients.id ASC LIMIT 1
|
198
180
|
```
|
199
181
|
|
200
|
-
`
|
201
|
-
|
202
|
-
#### `first!`
|
182
|
+
The `first` method returns `nil` if no matching record is found and no exception will be raised.
|
203
183
|
|
204
|
-
|
184
|
+
You can pass in a numerical argument to the `first` method to return up to that number of results. For example
|
205
185
|
|
206
186
|
```ruby
|
207
|
-
client = Client.first
|
208
|
-
# =>
|
187
|
+
client = Client.first(3)
|
188
|
+
# => [
|
189
|
+
#<Client id: 1, first_name: "Lifo">,
|
190
|
+
#<Client id: 2, first_name: "Fifo">,
|
191
|
+
#<Client id: 3, first_name: "Filo">
|
192
|
+
]
|
209
193
|
```
|
210
194
|
|
211
195
|
The SQL equivalent of the above is:
|
212
196
|
|
213
197
|
```sql
|
214
|
-
SELECT * FROM clients ORDER BY clients.id ASC LIMIT
|
198
|
+
SELECT * FROM clients ORDER BY clients.id ASC LIMIT 3
|
215
199
|
```
|
216
200
|
|
217
|
-
`
|
201
|
+
The `first!` method behaves exactly like `first`, except that it will raise `ActiveRecord::RecordNotFound` if no matching record is found.
|
218
202
|
|
219
|
-
#### `last
|
203
|
+
#### `last`
|
220
204
|
|
221
|
-
`
|
205
|
+
The `last` method finds the last record ordered by the primary key. For example:
|
222
206
|
|
223
207
|
```ruby
|
224
|
-
client = Client.last
|
208
|
+
client = Client.last
|
225
209
|
# => #<Client id: 221, first_name: "Russel">
|
226
210
|
```
|
227
211
|
|
@@ -231,92 +215,56 @@ The SQL equivalent of the above is:
|
|
231
215
|
SELECT * FROM clients ORDER BY clients.id DESC LIMIT 1
|
232
216
|
```
|
233
217
|
|
234
|
-
`
|
235
|
-
|
236
|
-
#### `find_by!`
|
237
|
-
|
238
|
-
`Model.find_by!` finds the first record matching some conditions. It raises `ActiveRecord::RecordNotFound` if no matching record is found. For example:
|
239
|
-
|
240
|
-
```ruby
|
241
|
-
Client.find_by! first_name: 'Lifo'
|
242
|
-
# => #<Client id: 1, first_name: "Lifo">
|
243
|
-
|
244
|
-
Client.find_by! first_name: 'Jon'
|
245
|
-
# => ActiveRecord::RecordNotFound
|
246
|
-
```
|
218
|
+
The `last` method returns `nil` if no matching record is found and no exception will be raised.
|
247
219
|
|
248
|
-
|
220
|
+
You can pass in a numerical argument to the `last` method to return up to that number of results. For example
|
249
221
|
|
250
222
|
```ruby
|
251
|
-
Client.
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
`Model.find(array_of_primary_key)` accepts an array of _primary keys_, returning an array containing all of the matching records for the supplied _primary keys_. For example:
|
259
|
-
|
260
|
-
```ruby
|
261
|
-
# Find the clients with primary keys 1 and 10.
|
262
|
-
client = Client.find([1, 10]) # Or even Client.find(1, 10)
|
263
|
-
# => [#<Client id: 1, first_name: "Lifo">, #<Client id: 10, first_name: "Ryan">]
|
223
|
+
client = Client.last(3)
|
224
|
+
# => [
|
225
|
+
#<Client id: 219, first_name: "James">,
|
226
|
+
#<Client id: 220, first_name: "Sara">,
|
227
|
+
#<Client id: 221, first_name: "Russel">
|
228
|
+
]
|
264
229
|
```
|
265
230
|
|
266
231
|
The SQL equivalent of the above is:
|
267
232
|
|
268
233
|
```sql
|
269
|
-
SELECT * FROM clients
|
234
|
+
SELECT * FROM clients ORDER BY clients.id DESC LIMIT 3
|
270
235
|
```
|
271
236
|
|
272
|
-
|
237
|
+
The `last!` method behaves exactly like `last`, except that it will raise `ActiveRecord::RecordNotFound` if no matching record is found.
|
273
238
|
|
274
|
-
####
|
239
|
+
#### `find_by`
|
275
240
|
|
276
|
-
`
|
241
|
+
The `find_by` method finds the first record matching some conditions. For example:
|
277
242
|
|
278
243
|
```ruby
|
279
|
-
Client.
|
280
|
-
# =>
|
281
|
-
#<Client id: 2, first_name: "Raf">]
|
282
|
-
```
|
283
|
-
|
284
|
-
The SQL equivalent of the above is:
|
244
|
+
Client.find_by first_name: 'Lifo'
|
245
|
+
# => #<Client id: 1, first_name: "Lifo">
|
285
246
|
|
286
|
-
|
287
|
-
|
247
|
+
Client.find_by first_name: 'Jon'
|
248
|
+
# => nil
|
288
249
|
```
|
289
250
|
|
290
|
-
|
291
|
-
|
292
|
-
`Model.first(limit)` finds the first number of records specified by `limit` ordered by primary key:
|
251
|
+
It is equivalent to writing:
|
293
252
|
|
294
253
|
```ruby
|
295
|
-
Client.
|
296
|
-
# => [#<Client id: 1, first_name: "Lifo">,
|
297
|
-
#<Client id: 2, first_name: "Raf">]
|
298
|
-
```
|
299
|
-
|
300
|
-
The SQL equivalent of the above is:
|
301
|
-
|
302
|
-
```sql
|
303
|
-
SELECT * FROM clients ORDER BY id ASC LIMIT 2
|
254
|
+
Client.where(first_name: 'Lifo').take
|
304
255
|
```
|
305
256
|
|
306
|
-
|
307
|
-
|
308
|
-
`Model.last(limit)` finds the number of records specified by `limit` ordered by primary key in descending order:
|
257
|
+
The `find_by!` method behaves exactly like `find_by`, except that it will raise `ActiveRecord::RecordNotFound` if no matching record is found. For example:
|
309
258
|
|
310
259
|
```ruby
|
311
|
-
Client.
|
312
|
-
# =>
|
313
|
-
#<Client id: 9, first_name: "John">]
|
260
|
+
Client.find_by! first_name: 'does not exist'
|
261
|
+
# => ActiveRecord::RecordNotFound
|
314
262
|
```
|
315
263
|
|
316
|
-
|
264
|
+
This is equivalent to writing:
|
317
265
|
|
318
|
-
```
|
319
|
-
|
266
|
+
```ruby
|
267
|
+
Client.where(first_name: 'does not exist').take!
|
320
268
|
```
|
321
269
|
|
322
270
|
### Retrieving Multiple Objects in Batches
|
@@ -328,7 +276,7 @@ This may appear straightforward:
|
|
328
276
|
```ruby
|
329
277
|
# This is very inefficient when the users table has thousands of rows.
|
330
278
|
User.all.each do |user|
|
331
|
-
|
279
|
+
NewsMailer.weekly(user).deliver_now
|
332
280
|
end
|
333
281
|
```
|
334
282
|
|
@@ -344,7 +292,15 @@ The `find_each` method retrieves a batch of records and then yields _each_ recor
|
|
344
292
|
|
345
293
|
```ruby
|
346
294
|
User.find_each do |user|
|
347
|
-
|
295
|
+
NewsMailer.weekly(user).deliver_now
|
296
|
+
end
|
297
|
+
```
|
298
|
+
|
299
|
+
To add conditions to a `find_each` operation you can chain other Active Record methods such as `where`:
|
300
|
+
|
301
|
+
```ruby
|
302
|
+
User.where(weekly_subscriber: true).find_each do |user|
|
303
|
+
NewsMailer.weekly(user).deliver_now
|
348
304
|
end
|
349
305
|
```
|
350
306
|
|
@@ -360,7 +316,7 @@ The `:batch_size` option allows you to specify the number of records to be retri
|
|
360
316
|
|
361
317
|
```ruby
|
362
318
|
User.find_each(batch_size: 5000) do |user|
|
363
|
-
|
319
|
+
NewsMailer.weekly(user).deliver_now
|
364
320
|
end
|
365
321
|
```
|
366
322
|
|
@@ -372,28 +328,24 @@ For example, to send newsletters only to users with the primary key starting fro
|
|
372
328
|
|
373
329
|
```ruby
|
374
330
|
User.find_each(start: 2000, batch_size: 5000) do |user|
|
375
|
-
|
331
|
+
NewsMailer.weekly(user).deliver_now
|
376
332
|
end
|
377
333
|
```
|
378
334
|
|
379
|
-
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 `:start` option on each worker.
|
380
|
-
|
381
335
|
#### `find_in_batches`
|
382
336
|
|
383
337
|
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:
|
384
338
|
|
385
339
|
```ruby
|
386
340
|
# Give add_invoices an array of 1000 invoices at a time
|
387
|
-
Invoice.find_in_batches
|
341
|
+
Invoice.find_in_batches do |invoices|
|
388
342
|
export.add_invoices(invoices)
|
389
343
|
end
|
390
344
|
```
|
391
345
|
|
392
|
-
NOTE: The `:include` option allows you to name associations that should be loaded alongside with the models.
|
393
|
-
|
394
346
|
##### Options for `find_in_batches`
|
395
347
|
|
396
|
-
The `find_in_batches` method accepts the same `:batch_size` and `:start` options as `find_each
|
348
|
+
The `find_in_batches` method accepts the same `:batch_size` and `:start` options as `find_each`.
|
397
349
|
|
398
350
|
Conditions
|
399
351
|
----------
|
@@ -472,8 +424,8 @@ Client.where('locked' => true)
|
|
472
424
|
In the case of a belongs_to relationship, an association key can be used to specify the model if an Active Record object is used as the value. This method works with polymorphic relationships as well.
|
473
425
|
|
474
426
|
```ruby
|
475
|
-
|
476
|
-
Author.joins(:
|
427
|
+
Article.where(author: author)
|
428
|
+
Author.joins(:articles).where(articles: { author: author })
|
477
429
|
```
|
478
430
|
|
479
431
|
NOTE: The values cannot be symbols. For example, you cannot do `Client.where(status: :active)`.
|
@@ -511,7 +463,7 @@ SELECT * FROM clients WHERE (clients.orders_count IN (1,3,5))
|
|
511
463
|
`NOT` SQL queries can be built by `where.not`.
|
512
464
|
|
513
465
|
```ruby
|
514
|
-
|
466
|
+
Article.where.not(author: author)
|
515
467
|
```
|
516
468
|
|
517
469
|
In other words, this query can be generated by calling `where` with no argument, then immediately chain with `not` passing `where` conditions.
|
@@ -659,6 +611,23 @@ FROM orders
|
|
659
611
|
GROUP BY date(created_at)
|
660
612
|
```
|
661
613
|
|
614
|
+
### Total of grouped items
|
615
|
+
|
616
|
+
To get the total of grouped items on a single query call `count` after the `group`.
|
617
|
+
|
618
|
+
```ruby
|
619
|
+
Order.group(:status).count
|
620
|
+
# => { 'awaiting_approval' => 7, 'paid' => 12 }
|
621
|
+
```
|
622
|
+
|
623
|
+
The SQL that would be executed would be something like this:
|
624
|
+
|
625
|
+
```sql
|
626
|
+
SELECT COUNT (*) AS count_all, status AS status
|
627
|
+
FROM "orders"
|
628
|
+
GROUP BY status
|
629
|
+
```
|
630
|
+
|
662
631
|
Having
|
663
632
|
------
|
664
633
|
|
@@ -690,32 +659,32 @@ Overriding Conditions
|
|
690
659
|
You can specify certain conditions to be removed using the `unscope` method. For example:
|
691
660
|
|
692
661
|
```ruby
|
693
|
-
|
662
|
+
Article.where('id > 10').limit(20).order('id asc').unscope(:order)
|
694
663
|
```
|
695
664
|
|
696
665
|
The SQL that would be executed:
|
697
666
|
|
698
667
|
```sql
|
699
|
-
SELECT * FROM
|
668
|
+
SELECT * FROM articles WHERE id > 10 LIMIT 20
|
700
669
|
|
701
670
|
# Original query without `unscope`
|
702
|
-
SELECT * FROM
|
671
|
+
SELECT * FROM articles WHERE id > 10 ORDER BY id asc LIMIT 20
|
703
672
|
|
704
673
|
```
|
705
674
|
|
706
|
-
You can
|
675
|
+
You can also unscope specific `where` clauses. For example:
|
707
676
|
|
708
677
|
```ruby
|
709
|
-
|
710
|
-
# SELECT "
|
678
|
+
Article.where(id: 10, trashed: false).unscope(where: :id)
|
679
|
+
# SELECT "articles".* FROM "articles" WHERE trashed = 0
|
711
680
|
```
|
712
681
|
|
713
682
|
A relation which has used `unscope` will affect any relation it is
|
714
683
|
merged in to:
|
715
684
|
|
716
685
|
```ruby
|
717
|
-
|
718
|
-
# SELECT "
|
686
|
+
Article.order('id asc').merge(Article.unscope(:order))
|
687
|
+
# SELECT "articles".* FROM "articles"
|
719
688
|
```
|
720
689
|
|
721
690
|
### `only`
|
@@ -723,16 +692,16 @@ Post.order('id asc').merge(Post.unscope(:order))
|
|
723
692
|
You can also override conditions using the `only` method. For example:
|
724
693
|
|
725
694
|
```ruby
|
726
|
-
|
695
|
+
Article.where('id > 10').limit(20).order('id desc').only(:order, :where)
|
727
696
|
```
|
728
697
|
|
729
698
|
The SQL that would be executed:
|
730
699
|
|
731
700
|
```sql
|
732
|
-
SELECT * FROM
|
701
|
+
SELECT * FROM articles WHERE id > 10 ORDER BY id DESC
|
733
702
|
|
734
703
|
# Original query without `only`
|
735
|
-
SELECT "
|
704
|
+
SELECT "articles".* FROM "articles" WHERE (id > 10) ORDER BY id desc LIMIT 20
|
736
705
|
|
737
706
|
```
|
738
707
|
|
@@ -741,27 +710,25 @@ SELECT "posts".* FROM "posts" WHERE (id > 10) ORDER BY id desc LIMIT 20
|
|
741
710
|
The `reorder` method overrides the default scope order. For example:
|
742
711
|
|
743
712
|
```ruby
|
744
|
-
class
|
745
|
-
..
|
746
|
-
..
|
713
|
+
class Article < ActiveRecord::Base
|
747
714
|
has_many :comments, -> { order('posted_at DESC') }
|
748
715
|
end
|
749
716
|
|
750
|
-
|
717
|
+
Article.find(10).comments.reorder('name')
|
751
718
|
```
|
752
719
|
|
753
720
|
The SQL that would be executed:
|
754
721
|
|
755
722
|
```sql
|
756
|
-
SELECT * FROM
|
757
|
-
SELECT * FROM comments WHERE
|
723
|
+
SELECT * FROM articles WHERE id = 10
|
724
|
+
SELECT * FROM comments WHERE article_id = 10 ORDER BY name
|
758
725
|
```
|
759
726
|
|
760
727
|
In case the `reorder` clause is not used, the SQL executed would be:
|
761
728
|
|
762
729
|
```sql
|
763
|
-
SELECT * FROM
|
764
|
-
SELECT * FROM comments WHERE
|
730
|
+
SELECT * FROM articles WHERE id = 10
|
731
|
+
SELECT * FROM comments WHERE article_id = 10 ORDER BY posted_at DESC
|
765
732
|
```
|
766
733
|
|
767
734
|
### `reverse_order`
|
@@ -797,25 +764,25 @@ This method accepts **no** arguments.
|
|
797
764
|
The `rewhere` method overrides an existing, named where condition. For example:
|
798
765
|
|
799
766
|
```ruby
|
800
|
-
|
767
|
+
Article.where(trashed: true).rewhere(trashed: false)
|
801
768
|
```
|
802
769
|
|
803
770
|
The SQL that would be executed:
|
804
771
|
|
805
772
|
```sql
|
806
|
-
SELECT * FROM
|
773
|
+
SELECT * FROM articles WHERE `trashed` = 0
|
807
774
|
```
|
808
775
|
|
809
776
|
In case the `rewhere` clause is not used,
|
810
777
|
|
811
778
|
```ruby
|
812
|
-
|
779
|
+
Article.where(trashed: true).where(trashed: false)
|
813
780
|
```
|
814
781
|
|
815
782
|
the SQL executed would be:
|
816
783
|
|
817
784
|
```sql
|
818
|
-
SELECT * FROM
|
785
|
+
SELECT * FROM articles WHERE `trashed` = 1 AND `trashed` = 0
|
819
786
|
```
|
820
787
|
|
821
788
|
Null Relation
|
@@ -824,21 +791,21 @@ Null Relation
|
|
824
791
|
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.
|
825
792
|
|
826
793
|
```ruby
|
827
|
-
|
794
|
+
Article.none # returns an empty Relation and fires no queries.
|
828
795
|
```
|
829
796
|
|
830
797
|
```ruby
|
831
|
-
# The
|
832
|
-
@
|
798
|
+
# The visible_articles method below is expected to return a Relation.
|
799
|
+
@articles = current_user.visible_articles.where(name: params[:name])
|
833
800
|
|
834
|
-
def
|
801
|
+
def visible_articles
|
835
802
|
case role
|
836
803
|
when 'Country Manager'
|
837
|
-
|
804
|
+
Article.where(country: country)
|
838
805
|
when 'Reviewer'
|
839
|
-
|
806
|
+
Article.published
|
840
807
|
when 'Bad User'
|
841
|
-
|
808
|
+
Article.none # => returning [] or nil breaks the caller code in this case
|
842
809
|
end
|
843
810
|
end
|
844
811
|
```
|
@@ -907,7 +874,7 @@ For example:
|
|
907
874
|
Item.transaction do
|
908
875
|
i = Item.lock.first
|
909
876
|
i.name = 'Jones'
|
910
|
-
i.save
|
877
|
+
i.save!
|
911
878
|
end
|
912
879
|
```
|
913
880
|
|
@@ -963,23 +930,23 @@ SELECT clients.* FROM clients LEFT OUTER JOIN addresses ON addresses.client_id =
|
|
963
930
|
|
964
931
|
WARNING: This method only works with `INNER JOIN`.
|
965
932
|
|
966
|
-
Active Record lets you use the names of the [associations](association_basics.html) defined on the model as a shortcut for specifying `JOIN`
|
933
|
+
Active Record lets you use the names of the [associations](association_basics.html) defined on the model as a shortcut for specifying `JOIN` clauses for those associations when using the `joins` method.
|
967
934
|
|
968
|
-
For example, consider the following `Category`, `
|
935
|
+
For example, consider the following `Category`, `Article`, `Comment`, `Guest` and `Tag` models:
|
969
936
|
|
970
937
|
```ruby
|
971
938
|
class Category < ActiveRecord::Base
|
972
|
-
has_many :
|
939
|
+
has_many :articles
|
973
940
|
end
|
974
941
|
|
975
|
-
class
|
942
|
+
class Article < ActiveRecord::Base
|
976
943
|
belongs_to :category
|
977
944
|
has_many :comments
|
978
945
|
has_many :tags
|
979
946
|
end
|
980
947
|
|
981
948
|
class Comment < ActiveRecord::Base
|
982
|
-
belongs_to :
|
949
|
+
belongs_to :article
|
983
950
|
has_one :guest
|
984
951
|
end
|
985
952
|
|
@@ -988,7 +955,7 @@ class Guest < ActiveRecord::Base
|
|
988
955
|
end
|
989
956
|
|
990
957
|
class Tag < ActiveRecord::Base
|
991
|
-
belongs_to :
|
958
|
+
belongs_to :article
|
992
959
|
end
|
993
960
|
```
|
994
961
|
|
@@ -997,64 +964,64 @@ Now all of the following will produce the expected join queries using `INNER JOI
|
|
997
964
|
#### Joining a Single Association
|
998
965
|
|
999
966
|
```ruby
|
1000
|
-
Category.joins(:
|
967
|
+
Category.joins(:articles)
|
1001
968
|
```
|
1002
969
|
|
1003
970
|
This produces:
|
1004
971
|
|
1005
972
|
```sql
|
1006
973
|
SELECT categories.* FROM categories
|
1007
|
-
INNER JOIN
|
974
|
+
INNER JOIN articles ON articles.category_id = categories.id
|
1008
975
|
```
|
1009
976
|
|
1010
|
-
Or, in English: "return a Category object for all categories with
|
977
|
+
Or, in English: "return a Category object for all categories with articles". Note that you will see duplicate categories if more than one article has the same category. If you want unique categories, you can use `Category.joins(:articles).uniq`.
|
1011
978
|
|
1012
979
|
#### Joining Multiple Associations
|
1013
980
|
|
1014
981
|
```ruby
|
1015
|
-
|
982
|
+
Article.joins(:category, :comments)
|
1016
983
|
```
|
1017
984
|
|
1018
985
|
This produces:
|
1019
986
|
|
1020
987
|
```sql
|
1021
|
-
SELECT
|
1022
|
-
INNER JOIN categories ON
|
1023
|
-
INNER JOIN comments ON comments.
|
988
|
+
SELECT articles.* FROM articles
|
989
|
+
INNER JOIN categories ON articles.category_id = categories.id
|
990
|
+
INNER JOIN comments ON comments.article_id = articles.id
|
1024
991
|
```
|
1025
992
|
|
1026
|
-
Or, in English: "return all
|
993
|
+
Or, in English: "return all articles that have a category and at least one comment". Note again that articles with multiple comments will show up multiple times.
|
1027
994
|
|
1028
995
|
#### Joining Nested Associations (Single Level)
|
1029
996
|
|
1030
997
|
```ruby
|
1031
|
-
|
998
|
+
Article.joins(comments: :guest)
|
1032
999
|
```
|
1033
1000
|
|
1034
1001
|
This produces:
|
1035
1002
|
|
1036
1003
|
```sql
|
1037
|
-
SELECT
|
1038
|
-
INNER JOIN comments ON comments.
|
1004
|
+
SELECT articles.* FROM articles
|
1005
|
+
INNER JOIN comments ON comments.article_id = articles.id
|
1039
1006
|
INNER JOIN guests ON guests.comment_id = comments.id
|
1040
1007
|
```
|
1041
1008
|
|
1042
|
-
Or, in English: "return all
|
1009
|
+
Or, in English: "return all articles that have a comment made by a guest."
|
1043
1010
|
|
1044
1011
|
#### Joining Nested Associations (Multiple Level)
|
1045
1012
|
|
1046
1013
|
```ruby
|
1047
|
-
Category.joins(
|
1014
|
+
Category.joins(articles: [{ comments: :guest }, :tags])
|
1048
1015
|
```
|
1049
1016
|
|
1050
1017
|
This produces:
|
1051
1018
|
|
1052
1019
|
```sql
|
1053
1020
|
SELECT categories.* FROM categories
|
1054
|
-
INNER JOIN
|
1055
|
-
INNER JOIN comments ON comments.
|
1021
|
+
INNER JOIN articles ON articles.category_id = categories.id
|
1022
|
+
INNER JOIN comments ON comments.article_id = articles.id
|
1056
1023
|
INNER JOIN guests ON guests.comment_id = comments.id
|
1057
|
-
INNER JOIN tags ON tags.
|
1024
|
+
INNER JOIN tags ON tags.article_id = articles.id
|
1058
1025
|
```
|
1059
1026
|
|
1060
1027
|
### Specifying Conditions on the Joined Tables
|
@@ -1123,18 +1090,18 @@ Active Record lets you eager load any number of associations with a single `Mode
|
|
1123
1090
|
#### Array of Multiple Associations
|
1124
1091
|
|
1125
1092
|
```ruby
|
1126
|
-
|
1093
|
+
Article.includes(:category, :comments)
|
1127
1094
|
```
|
1128
1095
|
|
1129
|
-
This loads all the
|
1096
|
+
This loads all the articles and the associated category and comments for each article.
|
1130
1097
|
|
1131
1098
|
#### Nested Associations Hash
|
1132
1099
|
|
1133
1100
|
```ruby
|
1134
|
-
Category.includes(
|
1101
|
+
Category.includes(articles: [{ comments: :guest }, :tags]).find(1)
|
1135
1102
|
```
|
1136
1103
|
|
1137
|
-
This will find the category with id 1 and eager load all of the associated
|
1104
|
+
This will find the category with id 1 and eager load all of the associated articles, the associated articles' tags and comments, and every comment's guest association.
|
1138
1105
|
|
1139
1106
|
### Specifying Conditions on Eager Loaded Associations
|
1140
1107
|
|
@@ -1143,29 +1110,30 @@ Even though Active Record lets you specify conditions on the eager loaded associ
|
|
1143
1110
|
However if you must do this, you may use `where` as you would normally.
|
1144
1111
|
|
1145
1112
|
```ruby
|
1146
|
-
|
1113
|
+
Article.includes(:comments).where(comments: { visible: true })
|
1147
1114
|
```
|
1148
1115
|
|
1149
1116
|
This would generate a query which contains a `LEFT OUTER JOIN` whereas the
|
1150
1117
|
`joins` method would generate one using the `INNER JOIN` function instead.
|
1151
1118
|
|
1152
1119
|
```ruby
|
1153
|
-
SELECT "
|
1120
|
+
SELECT "articles"."id" AS t0_r0, ... "comments"."updated_at" AS t1_r5 FROM "articles" LEFT OUTER JOIN "comments" ON "comments"."article_id" = "articles"."id" WHERE (comments.visible = 1)
|
1154
1121
|
```
|
1155
1122
|
|
1156
|
-
If there was no `where` condition, this would generate the normal set of two
|
1157
|
-
queries.
|
1123
|
+
If there was no `where` condition, this would generate the normal set of two queries.
|
1158
1124
|
|
1159
1125
|
NOTE: Using `where` like this will only work when you pass it a Hash. For
|
1160
1126
|
SQL-fragments you need use `references` to force joined tables:
|
1161
1127
|
|
1162
1128
|
```ruby
|
1163
|
-
|
1129
|
+
Article.includes(:comments).where("comments.visible = true").references(:comments)
|
1164
1130
|
```
|
1165
1131
|
|
1166
|
-
If, in the case of this `includes` query, there were no comments for any
|
1167
|
-
all the
|
1168
|
-
conditions **must** match, otherwise no records will be
|
1132
|
+
If, in the case of this `includes` query, there were no comments for any
|
1133
|
+
articles, all the articles would still be loaded. By using `joins` (an INNER
|
1134
|
+
JOIN), the join conditions **must** match, otherwise no records will be
|
1135
|
+
returned.
|
1136
|
+
|
1169
1137
|
|
1170
1138
|
|
1171
1139
|
Scopes
|
@@ -1176,7 +1144,7 @@ Scoping allows you to specify commonly-used queries which can be referenced as m
|
|
1176
1144
|
To define a simple scope, we use the `scope` method inside the class, passing the query that we'd like to run when this scope is called:
|
1177
1145
|
|
1178
1146
|
```ruby
|
1179
|
-
class
|
1147
|
+
class Article < ActiveRecord::Base
|
1180
1148
|
scope :published, -> { where(published: true) }
|
1181
1149
|
end
|
1182
1150
|
```
|
@@ -1184,7 +1152,7 @@ end
|
|
1184
1152
|
This is exactly the same as defining a class method, and which you use is a matter of personal preference:
|
1185
1153
|
|
1186
1154
|
```ruby
|
1187
|
-
class
|
1155
|
+
class Article < ActiveRecord::Base
|
1188
1156
|
def self.published
|
1189
1157
|
where(published: true)
|
1190
1158
|
end
|
@@ -1194,7 +1162,7 @@ end
|
|
1194
1162
|
Scopes are also chainable within scopes:
|
1195
1163
|
|
1196
1164
|
```ruby
|
1197
|
-
class
|
1165
|
+
class Article < ActiveRecord::Base
|
1198
1166
|
scope :published, -> { where(published: true) }
|
1199
1167
|
scope :published_and_commented, -> { published.where("comments_count > 0") }
|
1200
1168
|
end
|
@@ -1203,14 +1171,14 @@ end
|
|
1203
1171
|
To call this `published` scope we can call it on either the class:
|
1204
1172
|
|
1205
1173
|
```ruby
|
1206
|
-
|
1174
|
+
Article.published # => [published articles]
|
1207
1175
|
```
|
1208
1176
|
|
1209
|
-
Or on an association consisting of `
|
1177
|
+
Or on an association consisting of `Article` objects:
|
1210
1178
|
|
1211
1179
|
```ruby
|
1212
1180
|
category = Category.first
|
1213
|
-
category.
|
1181
|
+
category.articles.published # => [published articles belonging to this category]
|
1214
1182
|
```
|
1215
1183
|
|
1216
1184
|
### Passing in arguments
|
@@ -1218,7 +1186,7 @@ category.posts.published # => [published posts belonging to this category]
|
|
1218
1186
|
Your scope can take arguments:
|
1219
1187
|
|
1220
1188
|
```ruby
|
1221
|
-
class
|
1189
|
+
class Article < ActiveRecord::Base
|
1222
1190
|
scope :created_before, ->(time) { where("created_at < ?", time) }
|
1223
1191
|
end
|
1224
1192
|
```
|
@@ -1226,13 +1194,13 @@ end
|
|
1226
1194
|
Call the scope as if it were a class method:
|
1227
1195
|
|
1228
1196
|
```ruby
|
1229
|
-
|
1197
|
+
Article.created_before(Time.zone.now)
|
1230
1198
|
```
|
1231
1199
|
|
1232
1200
|
However, this is just duplicating the functionality that would be provided to you by a class method.
|
1233
1201
|
|
1234
1202
|
```ruby
|
1235
|
-
class
|
1203
|
+
class Article < ActiveRecord::Base
|
1236
1204
|
def self.created_before(time)
|
1237
1205
|
where("created_at < ?", time)
|
1238
1206
|
end
|
@@ -1242,7 +1210,36 @@ end
|
|
1242
1210
|
Using a class method is the preferred way to accept arguments for scopes. These methods will still be accessible on the association objects:
|
1243
1211
|
|
1244
1212
|
```ruby
|
1245
|
-
category.
|
1213
|
+
category.articles.created_before(time)
|
1214
|
+
```
|
1215
|
+
|
1216
|
+
### Applying a default scope
|
1217
|
+
|
1218
|
+
If we wish for a scope to be applied across all queries to the model we can use the
|
1219
|
+
`default_scope` method within the model itself.
|
1220
|
+
|
1221
|
+
```ruby
|
1222
|
+
class Client < ActiveRecord::Base
|
1223
|
+
default_scope { where("removed_at IS NULL") }
|
1224
|
+
end
|
1225
|
+
```
|
1226
|
+
|
1227
|
+
When queries are executed on this model, the SQL query will now look something like
|
1228
|
+
this:
|
1229
|
+
|
1230
|
+
```sql
|
1231
|
+
SELECT * FROM clients WHERE removed_at IS NULL
|
1232
|
+
```
|
1233
|
+
|
1234
|
+
If you need to do more complex things with a default scope, you can alternatively
|
1235
|
+
define it as a class method:
|
1236
|
+
|
1237
|
+
```ruby
|
1238
|
+
class Client < ActiveRecord::Base
|
1239
|
+
def self.default_scope
|
1240
|
+
# Should return an ActiveRecord::Relation.
|
1241
|
+
end
|
1242
|
+
end
|
1246
1243
|
```
|
1247
1244
|
|
1248
1245
|
### Merging of scopes
|
@@ -1298,36 +1295,6 @@ User.where(state: 'inactive')
|
|
1298
1295
|
As you can see above the `default_scope` is being merged in both
|
1299
1296
|
`scope` and `where` conditions.
|
1300
1297
|
|
1301
|
-
|
1302
|
-
### Applying a default scope
|
1303
|
-
|
1304
|
-
If we wish for a scope to be applied across all queries to the model we can use the
|
1305
|
-
`default_scope` method within the model itself.
|
1306
|
-
|
1307
|
-
```ruby
|
1308
|
-
class Client < ActiveRecord::Base
|
1309
|
-
default_scope { where("removed_at IS NULL") }
|
1310
|
-
end
|
1311
|
-
```
|
1312
|
-
|
1313
|
-
When queries are executed on this model, the SQL query will now look something like
|
1314
|
-
this:
|
1315
|
-
|
1316
|
-
```sql
|
1317
|
-
SELECT * FROM clients WHERE removed_at IS NULL
|
1318
|
-
```
|
1319
|
-
|
1320
|
-
If you need to do more complex things with a default scope, you can alternatively
|
1321
|
-
define it as a class method:
|
1322
|
-
|
1323
|
-
```ruby
|
1324
|
-
class Client < ActiveRecord::Base
|
1325
|
-
def self.default_scope
|
1326
|
-
# Should return an ActiveRecord::Relation.
|
1327
|
-
end
|
1328
|
-
end
|
1329
|
-
```
|
1330
|
-
|
1331
1298
|
### Removing All Scoping
|
1332
1299
|
|
1333
1300
|
If we wish to remove scoping for any reason we can use the `unscoped` method. This is
|
@@ -1470,6 +1437,11 @@ If you'd like to use your own SQL to find records in a table you can use `find_b
|
|
1470
1437
|
Client.find_by_sql("SELECT * FROM clients
|
1471
1438
|
INNER JOIN orders ON clients.id = orders.client_id
|
1472
1439
|
ORDER BY clients.created_at desc")
|
1440
|
+
# => [
|
1441
|
+
#<Client id: 1, first_name: "Lucas" >,
|
1442
|
+
#<Client id: 2, first_name: "Jan" >,
|
1443
|
+
# ...
|
1444
|
+
]
|
1473
1445
|
```
|
1474
1446
|
|
1475
1447
|
`find_by_sql` provides you with a simple way of making custom calls to the database and retrieving instantiated objects.
|
@@ -1479,12 +1451,16 @@ Client.find_by_sql("SELECT * FROM clients
|
|
1479
1451
|
`find_by_sql` 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.
|
1480
1452
|
|
1481
1453
|
```ruby
|
1482
|
-
Client.connection.select_all("SELECT
|
1454
|
+
Client.connection.select_all("SELECT first_name, created_at FROM clients WHERE id = '1'")
|
1455
|
+
# => [
|
1456
|
+
{"first_name"=>"Rafael", "created_at"=>"2012-11-10 23:23:45.281189"},
|
1457
|
+
{"first_name"=>"Eileen", "created_at"=>"2013-12-09 11:22:35.221282"}
|
1458
|
+
]
|
1483
1459
|
```
|
1484
1460
|
|
1485
1461
|
### `pluck`
|
1486
1462
|
|
1487
|
-
`pluck` can be used to query
|
1463
|
+
`pluck` can be used to query 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.
|
1488
1464
|
|
1489
1465
|
```ruby
|
1490
1466
|
Client.where(active: true).pluck(:id)
|
@@ -1606,20 +1582,20 @@ You can also use `any?` and `many?` to check for existence on a model or relatio
|
|
1606
1582
|
|
1607
1583
|
```ruby
|
1608
1584
|
# via a model
|
1609
|
-
|
1610
|
-
|
1585
|
+
Article.any?
|
1586
|
+
Article.many?
|
1611
1587
|
|
1612
1588
|
# via a named scope
|
1613
|
-
|
1614
|
-
|
1589
|
+
Article.recent.any?
|
1590
|
+
Article.recent.many?
|
1615
1591
|
|
1616
1592
|
# via a relation
|
1617
|
-
|
1618
|
-
|
1593
|
+
Article.where(published: true).any?
|
1594
|
+
Article.where(published: true).many?
|
1619
1595
|
|
1620
1596
|
# via an association
|
1621
|
-
|
1622
|
-
|
1597
|
+
Article.first.categories.any?
|
1598
|
+
Article.first.categories.many?
|
1623
1599
|
```
|
1624
1600
|
|
1625
1601
|
Calculations
|
@@ -1709,19 +1685,26 @@ Running EXPLAIN
|
|
1709
1685
|
You can run EXPLAIN on the queries triggered by relations. For example,
|
1710
1686
|
|
1711
1687
|
```ruby
|
1712
|
-
User.where(id: 1).joins(:
|
1688
|
+
User.where(id: 1).joins(:articles).explain
|
1713
1689
|
```
|
1714
1690
|
|
1715
1691
|
may yield
|
1716
1692
|
|
1717
1693
|
```
|
1718
|
-
EXPLAIN for: SELECT `users`.* FROM `users` INNER JOIN `
|
1719
|
-
|
1720
|
-
| id | select_type | table
|
1721
|
-
|
1722
|
-
| 1 | SIMPLE | users
|
1723
|
-
| 1 | SIMPLE |
|
1724
|
-
|
1694
|
+
EXPLAIN for: SELECT `users`.* FROM `users` INNER JOIN `articles` ON `articles`.`user_id` = `users`.`id` WHERE `users`.`id` = 1
|
1695
|
+
+----+-------------+----------+-------+---------------+
|
1696
|
+
| id | select_type | table | type | possible_keys |
|
1697
|
+
+----+-------------+----------+-------+---------------+
|
1698
|
+
| 1 | SIMPLE | users | const | PRIMARY |
|
1699
|
+
| 1 | SIMPLE | articles | ALL | NULL |
|
1700
|
+
+----+-------------+----------+-------+---------------+
|
1701
|
+
+---------+---------+-------+------+-------------+
|
1702
|
+
| key | key_len | ref | rows | Extra |
|
1703
|
+
+---------+---------+-------+------+-------------+
|
1704
|
+
| PRIMARY | 4 | const | 1 | |
|
1705
|
+
| NULL | NULL | NULL | 1 | Using where |
|
1706
|
+
+---------+---------+-------+------+-------------+
|
1707
|
+
|
1725
1708
|
2 rows in set (0.00 sec)
|
1726
1709
|
```
|
1727
1710
|
|
@@ -1731,15 +1714,15 @@ Active Record performs a pretty printing that emulates the one of the database
|
|
1731
1714
|
shells. So, the same query running with the PostgreSQL adapter would yield instead
|
1732
1715
|
|
1733
1716
|
```
|
1734
|
-
EXPLAIN for: SELECT "users".* FROM "users" INNER JOIN "
|
1717
|
+
EXPLAIN for: SELECT "users".* FROM "users" INNER JOIN "articles" ON "articles"."user_id" = "users"."id" WHERE "users"."id" = 1
|
1735
1718
|
QUERY PLAN
|
1736
1719
|
------------------------------------------------------------------------------
|
1737
1720
|
Nested Loop Left Join (cost=0.00..37.24 rows=8 width=0)
|
1738
|
-
Join Filter: (
|
1721
|
+
Join Filter: (articles.user_id = users.id)
|
1739
1722
|
-> Index Scan using users_pkey on users (cost=0.00..8.27 rows=1 width=4)
|
1740
1723
|
Index Cond: (id = 1)
|
1741
|
-
-> Seq Scan on
|
1742
|
-
Filter: (
|
1724
|
+
-> Seq Scan on articles (cost=0.00..28.88 rows=8 width=4)
|
1725
|
+
Filter: (articles.user_id = 1)
|
1743
1726
|
(6 rows)
|
1744
1727
|
```
|
1745
1728
|
|
@@ -1748,26 +1731,39 @@ may need the results of previous ones. Because of that, `explain` actually
|
|
1748
1731
|
executes the query, and then asks for the query plans. For example,
|
1749
1732
|
|
1750
1733
|
```ruby
|
1751
|
-
User.where(id: 1).includes(:
|
1734
|
+
User.where(id: 1).includes(:articles).explain
|
1752
1735
|
```
|
1753
1736
|
|
1754
1737
|
yields
|
1755
1738
|
|
1756
1739
|
```
|
1757
1740
|
EXPLAIN for: SELECT `users`.* FROM `users` WHERE `users`.`id` = 1
|
1758
|
-
|
1759
|
-
| id | select_type | table | type | possible_keys |
|
1760
|
-
|
1761
|
-
| 1 | SIMPLE | users | const | PRIMARY |
|
1762
|
-
|
1741
|
+
+----+-------------+-------+-------+---------------+
|
1742
|
+
| id | select_type | table | type | possible_keys |
|
1743
|
+
+----+-------------+-------+-------+---------------+
|
1744
|
+
| 1 | SIMPLE | users | const | PRIMARY |
|
1745
|
+
+----+-------------+-------+-------+---------------+
|
1746
|
+
+---------+---------+-------+------+-------+
|
1747
|
+
| key | key_len | ref | rows | Extra |
|
1748
|
+
+---------+---------+-------+------+-------+
|
1749
|
+
| PRIMARY | 4 | const | 1 | |
|
1750
|
+
+---------+---------+-------+------+-------+
|
1751
|
+
|
1763
1752
|
1 row in set (0.00 sec)
|
1764
1753
|
|
1765
|
-
EXPLAIN for: SELECT `
|
1766
|
-
|
1767
|
-
| id | select_type | table
|
1768
|
-
|
1769
|
-
| 1 | SIMPLE |
|
1770
|
-
|
1754
|
+
EXPLAIN for: SELECT `articles`.* FROM `articles` WHERE `articles`.`user_id` IN (1)
|
1755
|
+
+----+-------------+----------+------+---------------+
|
1756
|
+
| id | select_type | table | type | possible_keys |
|
1757
|
+
+----+-------------+----------+------+---------------+
|
1758
|
+
| 1 | SIMPLE | articles | ALL | NULL |
|
1759
|
+
+----+-------------+----------+------+---------------+
|
1760
|
+
+------+---------+------+------+-------------+
|
1761
|
+
| key | key_len | ref | rows | Extra |
|
1762
|
+
+------+---------+------+------+-------------+
|
1763
|
+
| NULL | NULL | NULL | 1 | Using where |
|
1764
|
+
+------+---------+------+------+-------------+
|
1765
|
+
|
1766
|
+
|
1771
1767
|
1 row in set (0.00 sec)
|
1772
1768
|
```
|
1773
1769
|
|