rails 4.1.16 → 4.2.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (141) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -3
  3. data/guides/CHANGELOG.md +13 -102
  4. data/guides/Rakefile +2 -2
  5. data/guides/assets/javascripts/guides.js +6 -0
  6. data/guides/assets/stylesheets/main.css +4 -1
  7. data/guides/bug_report_templates/action_controller_gem.rb +2 -2
  8. data/guides/bug_report_templates/action_controller_master.rb +5 -2
  9. data/guides/bug_report_templates/active_record_master.rb +2 -0
  10. data/guides/rails_guides.rb +2 -2
  11. data/guides/rails_guides/helpers.rb +1 -1
  12. data/guides/rails_guides/levenshtein.rb +29 -21
  13. data/guides/rails_guides/markdown.rb +6 -7
  14. data/guides/rails_guides/markdown/renderer.rb +1 -1
  15. data/guides/source/2_3_release_notes.md +3 -3
  16. data/guides/source/3_0_release_notes.md +4 -4
  17. data/guides/source/3_1_release_notes.md +2 -2
  18. data/guides/source/3_2_release_notes.md +2 -2
  19. data/guides/source/4_1_release_notes.md +8 -9
  20. data/guides/source/4_2_release_notes.md +572 -0
  21. data/guides/source/_license.html.erb +1 -1
  22. data/guides/source/_welcome.html.erb +2 -8
  23. data/guides/source/action_controller_overview.md +79 -7
  24. data/guides/source/action_mailer_basics.md +36 -11
  25. data/guides/source/action_view_overview.md +138 -119
  26. data/guides/source/active_job_basics.md +253 -0
  27. data/guides/source/active_model_basics.md +23 -0
  28. data/guides/source/active_record_basics.md +16 -15
  29. data/guides/source/active_record_callbacks.md +12 -9
  30. data/guides/source/{migrations.md → active_record_migrations.md} +90 -217
  31. data/guides/source/active_record_postgresql.md +437 -0
  32. data/guides/source/active_record_querying.md +261 -261
  33. data/guides/source/active_record_validations.md +7 -7
  34. data/guides/source/active_support_core_extensions.md +105 -44
  35. data/guides/source/active_support_instrumentation.md +3 -2
  36. data/guides/source/api_documentation_guidelines.md +62 -16
  37. data/guides/source/asset_pipeline.md +58 -46
  38. data/guides/source/association_basics.md +47 -38
  39. data/guides/source/caching_with_rails.md +31 -6
  40. data/guides/source/command_line.md +56 -25
  41. data/guides/source/configuring.md +98 -19
  42. data/guides/source/contributing_to_ruby_on_rails.md +174 -111
  43. data/guides/source/credits.html.erb +1 -1
  44. data/guides/source/debugging_rails_applications.md +438 -284
  45. data/guides/source/development_dependencies_install.md +17 -4
  46. data/guides/source/documents.yaml +11 -7
  47. data/guides/source/engines.md +192 -203
  48. data/guides/source/form_helpers.md +54 -45
  49. data/guides/source/generators.md +20 -11
  50. data/guides/source/getting_started.md +330 -191
  51. data/guides/source/i18n.md +92 -62
  52. data/guides/source/index.html.erb +1 -0
  53. data/guides/source/initialization.md +108 -59
  54. data/guides/source/layout.html.erb +1 -4
  55. data/guides/source/layouts_and_rendering.md +24 -23
  56. data/guides/source/nested_model_forms.md +3 -3
  57. data/guides/source/plugins.md +26 -26
  58. data/guides/source/rails_application_templates.md +21 -3
  59. data/guides/source/rails_on_rack.md +1 -1
  60. data/guides/source/routing.md +97 -71
  61. data/guides/source/ruby_on_rails_guides_guidelines.md +10 -12
  62. data/guides/source/security.md +39 -33
  63. data/guides/source/testing.md +111 -108
  64. data/guides/source/upgrading_ruby_on_rails.md +131 -14
  65. data/guides/source/working_with_javascript_in_rails.md +18 -16
  66. data/guides/w3c_validator.rb +2 -0
  67. metadata +37 -94
  68. data/guides/bug_report_templates/generic_gem.rb +0 -15
  69. data/guides/bug_report_templates/generic_master.rb +0 -26
  70. data/guides/code/getting_started/Gemfile +0 -40
  71. data/guides/code/getting_started/Gemfile.lock +0 -125
  72. data/guides/code/getting_started/README.rdoc +0 -28
  73. data/guides/code/getting_started/Rakefile +0 -6
  74. data/guides/code/getting_started/app/assets/javascripts/application.js +0 -15
  75. data/guides/code/getting_started/app/assets/javascripts/comments.js.coffee +0 -3
  76. data/guides/code/getting_started/app/assets/javascripts/posts.js.coffee +0 -3
  77. data/guides/code/getting_started/app/assets/javascripts/welcome.js.coffee +0 -3
  78. data/guides/code/getting_started/app/assets/stylesheets/application.css +0 -13
  79. data/guides/code/getting_started/app/assets/stylesheets/comments.css.scss +0 -3
  80. data/guides/code/getting_started/app/assets/stylesheets/posts.css.scss +0 -3
  81. data/guides/code/getting_started/app/assets/stylesheets/welcome.css.scss +0 -3
  82. data/guides/code/getting_started/app/controllers/application_controller.rb +0 -5
  83. data/guides/code/getting_started/app/controllers/comments_controller.rb +0 -23
  84. data/guides/code/getting_started/app/controllers/posts_controller.rb +0 -53
  85. data/guides/code/getting_started/app/controllers/welcome_controller.rb +0 -4
  86. data/guides/code/getting_started/app/helpers/application_helper.rb +0 -2
  87. data/guides/code/getting_started/app/helpers/comments_helper.rb +0 -2
  88. data/guides/code/getting_started/app/helpers/posts_helper.rb +0 -2
  89. data/guides/code/getting_started/app/helpers/welcome_helper.rb +0 -2
  90. data/guides/code/getting_started/app/models/comment.rb +0 -3
  91. data/guides/code/getting_started/app/models/post.rb +0 -7
  92. data/guides/code/getting_started/app/views/comments/_comment.html.erb +0 -15
  93. data/guides/code/getting_started/app/views/comments/_form.html.erb +0 -13
  94. data/guides/code/getting_started/app/views/layouts/application.html.erb +0 -14
  95. data/guides/code/getting_started/app/views/posts/_form.html.erb +0 -27
  96. data/guides/code/getting_started/app/views/posts/edit.html.erb +0 -5
  97. data/guides/code/getting_started/app/views/posts/index.html.erb +0 -21
  98. data/guides/code/getting_started/app/views/posts/new.html.erb +0 -5
  99. data/guides/code/getting_started/app/views/posts/show.html.erb +0 -18
  100. data/guides/code/getting_started/app/views/welcome/index.html.erb +0 -4
  101. data/guides/code/getting_started/bin/bundle +0 -4
  102. data/guides/code/getting_started/bin/rails +0 -4
  103. data/guides/code/getting_started/bin/rake +0 -4
  104. data/guides/code/getting_started/config.ru +0 -4
  105. data/guides/code/getting_started/config/application.rb +0 -18
  106. data/guides/code/getting_started/config/boot.rb +0 -4
  107. data/guides/code/getting_started/config/database.yml +0 -25
  108. data/guides/code/getting_started/config/environment.rb +0 -5
  109. data/guides/code/getting_started/config/environments/development.rb +0 -30
  110. data/guides/code/getting_started/config/environments/production.rb +0 -80
  111. data/guides/code/getting_started/config/environments/test.rb +0 -36
  112. data/guides/code/getting_started/config/initializers/backtrace_silencers.rb +0 -7
  113. data/guides/code/getting_started/config/initializers/filter_parameter_logging.rb +0 -4
  114. data/guides/code/getting_started/config/initializers/inflections.rb +0 -16
  115. data/guides/code/getting_started/config/initializers/locale.rb +0 -9
  116. data/guides/code/getting_started/config/initializers/mime_types.rb +0 -5
  117. data/guides/code/getting_started/config/initializers/secret_token.rb +0 -12
  118. data/guides/code/getting_started/config/initializers/session_store.rb +0 -3
  119. data/guides/code/getting_started/config/initializers/wrap_parameters.rb +0 -14
  120. data/guides/code/getting_started/config/locales/en.yml +0 -23
  121. data/guides/code/getting_started/config/routes.rb +0 -7
  122. data/guides/code/getting_started/db/migrate/20130122042648_create_posts.rb +0 -10
  123. data/guides/code/getting_started/db/migrate/20130122045842_create_comments.rb +0 -11
  124. data/guides/code/getting_started/db/schema.rb +0 -33
  125. data/guides/code/getting_started/db/seeds.rb +0 -7
  126. data/guides/code/getting_started/public/404.html +0 -60
  127. data/guides/code/getting_started/public/422.html +0 -60
  128. data/guides/code/getting_started/public/500.html +0 -59
  129. data/guides/code/getting_started/public/favicon.ico +0 -0
  130. data/guides/code/getting_started/public/robots.txt +0 -5
  131. data/guides/code/getting_started/test/controllers/comments_controller_test.rb +0 -7
  132. data/guides/code/getting_started/test/controllers/posts_controller_test.rb +0 -7
  133. data/guides/code/getting_started/test/controllers/welcome_controller_test.rb +0 -9
  134. data/guides/code/getting_started/test/fixtures/comments.yml +0 -11
  135. data/guides/code/getting_started/test/fixtures/posts.yml +0 -9
  136. data/guides/code/getting_started/test/helpers/comments_helper_test.rb +0 -4
  137. data/guides/code/getting_started/test/helpers/posts_helper_test.rb +0 -4
  138. data/guides/code/getting_started/test/helpers/welcome_helper_test.rb +0 -4
  139. data/guides/code/getting_started/test/models/comment_test.rb +0 -7
  140. data/guides/code/getting_started/test/models/post_test.rb +0 -7
  141. data/guides/code/getting_started/test/test_helper.rb +0 -12
@@ -0,0 +1,437 @@
1
+ Active Record and PostgreSQL
2
+ ============================
3
+
4
+ This guide covers PostgreSQL specific usage of Active Record.
5
+
6
+ After reading this guide, you will know:
7
+
8
+ * How to use PostgreSQL's datatypes.
9
+ * How to use UUID primary keys.
10
+ * How to implement full text search with PostgreSQL.
11
+ * How to back your Active Record models with database views.
12
+
13
+ --------------------------------------------------------------------------------
14
+
15
+ In order to use the PostgreSQL adapter you need to have at least version 8.2
16
+ installed. Older versions are not supported.
17
+
18
+ To get started with PostgreSQL have a look at the
19
+ [configuring Rails guide](configuring.html#configuring-a-postgresql-database).
20
+ It describes how to properly setup Active Record for PostgreSQL.
21
+
22
+ Datatypes
23
+ ---------
24
+
25
+ PostgreSQL offers a number of specific datatypes. Following is a list of types,
26
+ that are supported by the PostgreSQL adapter.
27
+
28
+ ### Bytea
29
+
30
+ * [type definition](http://www.postgresql.org/docs/9.3/static/datatype-binary.html)
31
+ * [functions and operators](http://www.postgresql.org/docs/9.3/static/functions-binarystring.html)
32
+
33
+ ```ruby
34
+ # db/migrate/20140207133952_create_documents.rb
35
+ create_table :documents do |t|
36
+ t.binary 'payload'
37
+ end
38
+
39
+ # app/models/document.rb
40
+ class Document < ActiveRecord::Base
41
+ end
42
+
43
+ # Usage
44
+ data = File.read(Rails.root + "tmp/output.pdf")
45
+ Document.create payload: data
46
+ ```
47
+
48
+ ### Array
49
+
50
+ * [type definition](http://www.postgresql.org/docs/9.3/static/arrays.html)
51
+ * [functions and operators](http://www.postgresql.org/docs/9.3/static/functions-array.html)
52
+
53
+ ```ruby
54
+ # db/migrate/20140207133952_create_books.rb
55
+ create_table :books do |t|
56
+ t.string 'title'
57
+ t.string 'tags', array: true
58
+ t.integer 'ratings', array: true
59
+ end
60
+ add_index :books, :tags, using: 'gin'
61
+ add_index :books, :ratings, using: 'gin'
62
+
63
+ # app/models/book.rb
64
+ class Book < ActiveRecord::Base
65
+ end
66
+
67
+ # Usage
68
+ Book.create title: "Brave New World",
69
+ tags: ["fantasy", "fiction"],
70
+ ratings: [4, 5]
71
+
72
+ ## Books for a single tag
73
+ Book.where("'fantasy' = ANY (tags)")
74
+
75
+ ## Books for multiple tags
76
+ Book.where("tags @> ARRAY[?]::varchar[]", ["fantasy", "fiction"])
77
+
78
+ ## Books with 3 or more ratings
79
+ Book.where("array_length(ratings, 1) >= 3")
80
+ ```
81
+
82
+ ### Hstore
83
+
84
+ * [type definition](http://www.postgresql.org/docs/9.3/static/hstore.html)
85
+
86
+ ```ruby
87
+ # db/migrate/20131009135255_create_profiles.rb
88
+ ActiveRecord::Schema.define do
89
+ create_table :profiles do |t|
90
+ t.hstore 'settings'
91
+ end
92
+ end
93
+
94
+ # app/models/profile.rb
95
+ class Profile < ActiveRecord::Base
96
+ end
97
+
98
+ # Usage
99
+ Profile.create(settings: { "color" => "blue", "resolution" => "800x600" })
100
+
101
+ profile = Profile.first
102
+ profile.settings # => {"color"=>"blue", "resolution"=>"800x600"}
103
+
104
+ profile.settings = {"color" => "yellow", "resolution" => "1280x1024"}
105
+ profile.save!
106
+
107
+ ## you need to call _will_change! if you are editing the store in place
108
+ profile.settings["color"] = "green"
109
+ profile.settings_will_change!
110
+ profile.save!
111
+ ```
112
+
113
+ ### JSON
114
+
115
+ * [type definition](http://www.postgresql.org/docs/9.3/static/datatype-json.html)
116
+ * [functions and operators](http://www.postgresql.org/docs/9.3/static/functions-json.html)
117
+
118
+ ```ruby
119
+ # db/migrate/20131220144913_create_events.rb
120
+ create_table :events do |t|
121
+ t.json 'payload'
122
+ end
123
+
124
+ # app/models/event.rb
125
+ class Event < ActiveRecord::Base
126
+ end
127
+
128
+ # Usage
129
+ Event.create(payload: { kind: "user_renamed", change: ["jack", "john"]})
130
+
131
+ event = Event.first
132
+ event.payload # => {"kind"=>"user_renamed", "change"=>["jack", "john"]}
133
+
134
+ ## Query based on JSON document
135
+ Event.where("payload->'kind' = ?", "user_renamed")
136
+ ```
137
+
138
+ ### Range Types
139
+
140
+ * [type definition](http://www.postgresql.org/docs/9.3/static/rangetypes.html)
141
+ * [functions and operators](http://www.postgresql.org/docs/9.3/static/functions-range.html)
142
+
143
+ This type is mapped to Ruby [`Range`](http://www.ruby-doc.org/core-2.1.1/Range.html) objects.
144
+
145
+ ```ruby
146
+ # db/migrate/20130923065404_create_events.rb
147
+ create_table :events do |t|
148
+ t.daterange 'duration'
149
+ end
150
+
151
+ # app/models/event.rb
152
+ class Event < ActiveRecord::Base
153
+ end
154
+
155
+ # Usage
156
+ Event.create(duration: Date.new(2014, 2, 11)..Date.new(2014, 2, 12))
157
+
158
+ event = Event.first
159
+ event.duration # => Tue, 11 Feb 2014...Thu, 13 Feb 2014
160
+
161
+ ## All Events on a given date
162
+ Event.where("duration @> ?::date", Date.new(2014, 2, 12))
163
+
164
+ ## Working with range bounds
165
+ event = Event.
166
+ select("lower(duration) AS starts_at").
167
+ select("upper(duration) AS ends_at").first
168
+
169
+ event.starts_at # => Tue, 11 Feb 2014
170
+ event.ends_at # => Thu, 13 Feb 2014
171
+ ```
172
+
173
+ ### Composite Types
174
+
175
+ * [type definition](http://www.postgresql.org/docs/9.3/static/rowtypes.html)
176
+
177
+ Currently there is no special support for composite types. They are mapped to
178
+ normal text columns:
179
+
180
+ ```sql
181
+ CREATE TYPE full_address AS
182
+ (
183
+ city VARCHAR(90),
184
+ street VARCHAR(90)
185
+ );
186
+ ```
187
+
188
+ ```ruby
189
+ # db/migrate/20140207133952_create_contacts.rb
190
+ execute <<-SQL
191
+ CREATE TYPE full_address AS
192
+ (
193
+ city VARCHAR(90),
194
+ street VARCHAR(90)
195
+ );
196
+ SQL
197
+ create_table :contacts do |t|
198
+ t.column :address, :full_address
199
+ end
200
+
201
+ # app/models/contact.rb
202
+ class Contact < ActiveRecord::Base
203
+ end
204
+
205
+ # Usage
206
+ Contact.create address: "(Paris,Champs-Élysées)"
207
+ contact = Contact.first
208
+ contact.address # => "(Paris,Champs-Élysées)"
209
+ contact.address = "(Paris,Rue Basse)"
210
+ contact.save!
211
+ ```
212
+
213
+ ### Enumerated Types
214
+
215
+ * [type definition](http://www.postgresql.org/docs/9.3/static/datatype-enum.html)
216
+
217
+ Currently there is no special support for enumerated types. They are mapped as
218
+ normal text columns:
219
+
220
+ ```ruby
221
+ # db/migrate/20131220144913_create_events.rb
222
+ execute <<-SQL
223
+ CREATE TYPE article_status AS ENUM ('draft', 'published');
224
+ SQL
225
+ create_table :articles do |t|
226
+ t.column :status, :article_status
227
+ end
228
+
229
+ # app/models/article.rb
230
+ class Article < ActiveRecord::Base
231
+ end
232
+
233
+ # Usage
234
+ Article.create status: "draft"
235
+ article = Article.first
236
+ article.status # => "draft"
237
+
238
+ article.status = "published"
239
+ article.save!
240
+ ```
241
+
242
+ ### UUID
243
+
244
+ * [type definition](http://www.postgresql.org/docs/9.3/static/datatype-uuid.html)
245
+ * [generator functions](http://www.postgresql.org/docs/9.3/static/uuid-ossp.html)
246
+
247
+
248
+ ```ruby
249
+ # db/migrate/20131220144913_create_revisions.rb
250
+ create_table :revisions do |t|
251
+ t.column :identifier, :uuid
252
+ end
253
+
254
+ # app/models/revision.rb
255
+ class Revision < ActiveRecord::Base
256
+ end
257
+
258
+ # Usage
259
+ Revision.create identifier: "A0EEBC99-9C0B-4EF8-BB6D-6BB9BD380A11"
260
+
261
+ revision = Revision.first
262
+ revision.identifier # => "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11"
263
+ ```
264
+
265
+ ### Bit String Types
266
+
267
+ * [type definition](http://www.postgresql.org/docs/9.3/static/datatype-bit.html)
268
+ * [functions and operators](http://www.postgresql.org/docs/9.3/static/functions-bitstring.html)
269
+
270
+ ```ruby
271
+ # db/migrate/20131220144913_create_users.rb
272
+ create_table :users, force: true do |t|
273
+ t.column :settings, "bit(8)"
274
+ end
275
+
276
+ # app/models/device.rb
277
+ class User < ActiveRecord::Base
278
+ end
279
+
280
+ # Usage
281
+ User.create settings: "01010011"
282
+ user = User.first
283
+ user.settings # => "(Paris,Champs-Élysées)"
284
+ user.settings = "0xAF"
285
+ user.settings # => 10101111
286
+ user.save!
287
+ ```
288
+
289
+ ### Network Address Types
290
+
291
+ * [type definition](http://www.postgresql.org/docs/9.3/static/datatype-net-types.html)
292
+
293
+ The types `inet` and `cidr` are mapped to Ruby
294
+ [`IPAddr`](http://www.ruby-doc.org/stdlib-2.1.1/libdoc/ipaddr/rdoc/IPAddr.html)
295
+ objects. The `macaddr` type is mapped to normal text.
296
+
297
+ ```ruby
298
+ # db/migrate/20140508144913_create_devices.rb
299
+ create_table(:devices, force: true) do |t|
300
+ t.inet 'ip'
301
+ t.cidr 'network'
302
+ t.macaddr 'address'
303
+ end
304
+
305
+ # app/models/device.rb
306
+ class Device < ActiveRecord::Base
307
+ end
308
+
309
+ # Usage
310
+ macbook = Device.create(ip: "192.168.1.12",
311
+ network: "192.168.2.0/24",
312
+ address: "32:01:16:6d:05:ef")
313
+
314
+ macbook.ip
315
+ # => #<IPAddr: IPv4:192.168.1.12/255.255.255.255>
316
+
317
+ macbook.network
318
+ # => #<IPAddr: IPv4:192.168.2.0/255.255.255.0>
319
+
320
+ macbook.address
321
+ # => "32:01:16:6d:05:ef"
322
+ ```
323
+
324
+ ### Geometric Types
325
+
326
+ * [type definition](http://www.postgresql.org/docs/9.3/static/datatype-geometric.html)
327
+
328
+ All geometric types, with the exception of `points` are mapped to normal text.
329
+ A point is casted to an array containing `x` and `y` coordinates.
330
+
331
+
332
+ UUID Primary Keys
333
+ -----------------
334
+
335
+ NOTE: you need to enable the `uuid-ossp` extension to generate UUIDs.
336
+
337
+ ```ruby
338
+ # db/migrate/20131220144913_create_devices.rb
339
+ enable_extension 'uuid-ossp' unless extension_enabled?('uuid-ossp')
340
+ create_table :devices, id: :uuid, default: 'uuid_generate_v4()' do |t|
341
+ t.string :kind
342
+ end
343
+
344
+ # app/models/device.rb
345
+ class Device < ActiveRecord::Base
346
+ end
347
+
348
+ # Usage
349
+ device = Device.create
350
+ device.id # => "814865cd-5a1d-4771-9306-4268f188fe9e"
351
+ ```
352
+
353
+ Full Text Search
354
+ ----------------
355
+
356
+ ```ruby
357
+ # db/migrate/20131220144913_create_documents.rb
358
+ create_table :documents do |t|
359
+ t.string 'title'
360
+ t.string 'body'
361
+ end
362
+
363
+ execute "CREATE INDEX documents_idx ON documents USING gin(to_tsvector('english', title || ' ' || body));"
364
+
365
+ # app/models/document.rb
366
+ class Document < ActiveRecord::Base
367
+ end
368
+
369
+ # Usage
370
+ Document.create(title: "Cats and Dogs", body: "are nice!")
371
+
372
+ ## all documents matching 'cat & dog'
373
+ Document.where("to_tsvector('english', title || ' ' || body) @@ to_tsquery(?)",
374
+ "cat & dog")
375
+ ```
376
+
377
+ Database Views
378
+ --------------
379
+
380
+ * [view creation](http://www.postgresql.org/docs/9.3/static/sql-createview.html)
381
+
382
+ Imagine you need to work with a legacy database containing the following table:
383
+
384
+ ```
385
+ rails_pg_guide=# \d "TBL_ART"
386
+ Table "public.TBL_ART"
387
+ Column | Type | Modifiers
388
+ ------------+-----------------------------+------------------------------------------------------------
389
+ INT_ID | integer | not null default nextval('"TBL_ART_INT_ID_seq"'::regclass)
390
+ STR_TITLE | character varying |
391
+ STR_STAT | character varying | default 'draft'::character varying
392
+ DT_PUBL_AT | timestamp without time zone |
393
+ BL_ARCH | boolean | default false
394
+ Indexes:
395
+ "TBL_ART_pkey" PRIMARY KEY, btree ("INT_ID")
396
+ ```
397
+
398
+ This table does not follow the Rails conventions at all.
399
+ Because simple PostgreSQL views are updateable by default,
400
+ we can wrap it as follows:
401
+
402
+ ```ruby
403
+ # db/migrate/20131220144913_create_articles_view.rb
404
+ execute <<-SQL
405
+ CREATE VIEW articles AS
406
+ SELECT "INT_ID" AS id,
407
+ "STR_TITLE" AS title,
408
+ "STR_STAT" AS status,
409
+ "DT_PUBL_AT" AS published_at,
410
+ "BL_ARCH" AS archived
411
+ FROM "TBL_ART"
412
+ WHERE "BL_ARCH" = 'f'
413
+ SQL
414
+
415
+ # app/models/article.rb
416
+ class Article < ActiveRecord::Base
417
+ self.primary_key = "id"
418
+ def archive!
419
+ update_attribute :archived, true
420
+ end
421
+ end
422
+
423
+ # Usage
424
+ first = Article.create! title: "Winter is coming",
425
+ status: "published",
426
+ published_at: 1.year.ago
427
+ second = Article.create! title: "Brace yourself",
428
+ status: "draft",
429
+ published_at: 1.month.ago
430
+
431
+ Article.count # => 1
432
+ first.archive!
433
+ Article.count # => 2
434
+ ```
435
+
436
+ NOTE: This application only cares about non-archived `Articles`. A view also
437
+ allows for conditions so we can exclude the archived `Articles` directly.
@@ -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
- #### Using a Primary Key
96
+ #### `find`
97
97
 
98
- Using `Model.find(primary_key)`, you can retrieve the object corresponding to the specified _primary key_ that matches any supplied options. For example:
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
- `Model.find(primary_key)` will raise an `ActiveRecord::RecordNotFound` exception if no matching record is found.
112
+ The `find` method will raise an `ActiveRecord::RecordNotFound` exception if no matching record is found.
113
113
 
114
- #### `take`
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
- client = Client.take
120
- # => #<Client id: 1, first_name: "Lifo">
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 LIMIT 1
125
+ SELECT * FROM clients WHERE (clients.id IN (1,10))
127
126
  ```
128
127
 
129
- `Model.take` returns `nil` if no record is found and no exception will be raised.
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
- #### `first`
130
+ #### `take`
134
131
 
135
- `Model.first` finds the first record ordered by the primary key. For example:
132
+ The `take` method retrieves a record without any implicit ordering. For example:
136
133
 
137
134
  ```ruby
138
- client = Client.first
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 ORDER BY clients.id ASC LIMIT 1
142
+ SELECT * FROM clients LIMIT 1
146
143
  ```
147
144
 
148
- `Model.first` returns `nil` if no matching record is found and no exception will be raised.
145
+ The `take` method returns `nil` if no record is found and no exception will be raised.
149
146
 
150
- #### `last`
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.last
156
- # => #<Client id: 221, first_name: "Russel">
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 ORDER BY clients.id DESC LIMIT 1
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
- It is equivalent to writing:
163
+ The `take!` method behaves exactly like `take`, except that it will raise `ActiveRecord::RecordNotFound` if no matching record is found.
180
164
 
181
- ```ruby
182
- Client.where(first_name: 'Lifo').take
183
- ```
165
+ TIP: The retrieved record may vary depending on the database engine.
184
166
 
185
- #### `take!`
167
+ #### `first`
186
168
 
187
- `Model.take!` retrieves a record without any implicit ordering. For example:
169
+ The `first` method finds the first record ordered by the primary key. For example:
188
170
 
189
171
  ```ruby
190
- client = Client.take!
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
- `Model.take!` raises `ActiveRecord::RecordNotFound` if no matching record is found.
201
-
202
- #### `first!`
182
+ The `first` method returns `nil` if no matching record is found and no exception will be raised.
203
183
 
204
- `Model.first!` finds the first record ordered by the primary key. For example:
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
- # => #<Client id: 1, first_name: "Lifo">
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 1
198
+ SELECT * FROM clients ORDER BY clients.id ASC LIMIT 3
215
199
  ```
216
200
 
217
- `Model.first!` raises `ActiveRecord::RecordNotFound` if no matching record is found.
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
- `Model.last!` finds the last record ordered by the primary key. For example:
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
- `Model.last!` raises `ActiveRecord::RecordNotFound` if no matching record is found.
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
- ```
247
-
248
- It is equivalent to writing:
249
-
250
- ```ruby
251
- Client.where(first_name: 'Lifo').take!
252
- ```
253
-
254
- ### Retrieving Multiple Objects
255
-
256
- #### Using Multiple Primary Keys
218
+ The `last` method returns `nil` if no matching record is found and no exception will be raised.
257
219
 
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:
220
+ You can pass in a numerical argument to the `last` method to return up to that number of results. For example
259
221
 
260
222
  ```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 WHERE (clients.id IN (1,10))
234
+ SELECT * FROM clients ORDER BY clients.id DESC LIMIT 3
270
235
  ```
271
236
 
272
- WARNING: `Model.find(array_of_primary_key)` will raise an `ActiveRecord::RecordNotFound` exception unless a matching record is found for **all** of the supplied primary keys.
237
+ The `last!` method behaves exactly like `last`, except that it will raise `ActiveRecord::RecordNotFound` if no matching record is found.
273
238
 
274
- #### take
239
+ #### `find_by`
275
240
 
276
- `Model.take(limit)` retrieves the first number of records specified by `limit` without any explicit ordering:
241
+ The `find_by` method finds the first record matching some conditions. For example:
277
242
 
278
243
  ```ruby
279
- Client.take(2)
280
- # => [#<Client id: 1, first_name: "Lifo">,
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
- ```sql
287
- SELECT * FROM clients LIMIT 2
247
+ Client.find_by first_name: 'Jon'
248
+ # => nil
288
249
  ```
289
250
 
290
- #### first
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.first(2)
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
- #### last
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.last(2)
312
- # => [#<Client id: 10, first_name: "Ryan">,
313
- #<Client id: 9, first_name: "John">]
260
+ Client.find_by! first_name: 'does not exist'
261
+ # => ActiveRecord::RecordNotFound
314
262
  ```
315
263
 
316
- The SQL equivalent of the above is:
264
+ This is equivalent to writing:
317
265
 
318
- ```sql
319
- SELECT * FROM clients ORDER BY id DESC LIMIT 2
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
- NewsLetter.weekly_deliver(user)
279
+ NewsMailer.weekly(user).deliver
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
- NewsLetter.weekly_deliver(user)
295
+ NewsMailer.weekly(user).deliver
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
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
- NewsLetter.weekly_deliver(user)
319
+ NewsMailer.weekly(user).deliver
364
320
  end
365
321
  ```
366
322
 
@@ -372,7 +328,7 @@ 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
- NewsLetter.weekly_deliver(user)
331
+ NewsMailer.weekly(user).deliver
376
332
  end
377
333
  ```
378
334
 
@@ -472,8 +428,8 @@ Client.where('locked' => true)
472
428
  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
429
 
474
430
  ```ruby
475
- Post.where(author: author)
476
- Author.joins(:posts).where(posts: { author: author })
431
+ Article.where(author: author)
432
+ Author.joins(:articles).where(articles: { author: author })
477
433
  ```
478
434
 
479
435
  NOTE: The values cannot be symbols. For example, you cannot do `Client.where(status: :active)`.
@@ -511,7 +467,7 @@ SELECT * FROM clients WHERE (clients.orders_count IN (1,3,5))
511
467
  `NOT` SQL queries can be built by `where.not`.
512
468
 
513
469
  ```ruby
514
- Post.where.not(author: author)
470
+ Article.where.not(author: author)
515
471
  ```
516
472
 
517
473
  In other words, this query can be generated by calling `where` with no argument, then immediately chain with `not` passing `where` conditions.
@@ -659,6 +615,23 @@ FROM orders
659
615
  GROUP BY date(created_at)
660
616
  ```
661
617
 
618
+ ### Total of grouped items
619
+
620
+ To get the total of grouped items on a single query call `count` after the `group`.
621
+
622
+ ```ruby
623
+ Order.group(:status).count
624
+ # => { 'awaiting_approval' => 7, 'paid' => 12 }
625
+ ```
626
+
627
+ The SQL that would be executed would be something like this:
628
+
629
+ ```sql
630
+ SELECT COUNT (*) AS count_all, status AS status
631
+ FROM "orders"
632
+ GROUP BY status
633
+ ```
634
+
662
635
  Having
663
636
  ------
664
637
 
@@ -690,32 +663,32 @@ Overriding Conditions
690
663
  You can specify certain conditions to be removed using the `unscope` method. For example:
691
664
 
692
665
  ```ruby
693
- Post.where('id > 10').limit(20).order('id asc').except(:order)
666
+ Article.where('id > 10').limit(20).order('id asc').unscope(:order)
694
667
  ```
695
668
 
696
669
  The SQL that would be executed:
697
670
 
698
671
  ```sql
699
- SELECT * FROM posts WHERE id > 10 LIMIT 20
672
+ SELECT * FROM articles WHERE id > 10 LIMIT 20
700
673
 
701
674
  # Original query without `unscope`
702
- SELECT * FROM posts WHERE id > 10 ORDER BY id asc LIMIT 20
675
+ SELECT * FROM articles WHERE id > 10 ORDER BY id asc LIMIT 20
703
676
 
704
677
  ```
705
678
 
706
- You can additionally unscope specific where clauses. For example:
679
+ You can also unscope specific `where` clauses. For example:
707
680
 
708
681
  ```ruby
709
- Post.where(id: 10, trashed: false).unscope(where: :id)
710
- # SELECT "posts".* FROM "posts" WHERE trashed = 0
682
+ Article.where(id: 10, trashed: false).unscope(where: :id)
683
+ # SELECT "articles".* FROM "articles" WHERE trashed = 0
711
684
  ```
712
685
 
713
686
  A relation which has used `unscope` will affect any relation it is
714
687
  merged in to:
715
688
 
716
689
  ```ruby
717
- Post.order('id asc').merge(Post.unscope(:order))
718
- # SELECT "posts".* FROM "posts"
690
+ Article.order('id asc').merge(Article.unscope(:order))
691
+ # SELECT "articles".* FROM "articles"
719
692
  ```
720
693
 
721
694
  ### `only`
@@ -723,16 +696,16 @@ Post.order('id asc').merge(Post.unscope(:order))
723
696
  You can also override conditions using the `only` method. For example:
724
697
 
725
698
  ```ruby
726
- Post.where('id > 10').limit(20).order('id desc').only(:order, :where)
699
+ Article.where('id > 10').limit(20).order('id desc').only(:order, :where)
727
700
  ```
728
701
 
729
702
  The SQL that would be executed:
730
703
 
731
704
  ```sql
732
- SELECT * FROM posts WHERE id > 10 ORDER BY id DESC
705
+ SELECT * FROM articles WHERE id > 10 ORDER BY id DESC
733
706
 
734
707
  # Original query without `only`
735
- SELECT "posts".* FROM "posts" WHERE (id > 10) ORDER BY id desc LIMIT 20
708
+ SELECT "articles".* FROM "articles" WHERE (id > 10) ORDER BY id desc LIMIT 20
736
709
 
737
710
  ```
738
711
 
@@ -741,27 +714,25 @@ SELECT "posts".* FROM "posts" WHERE (id > 10) ORDER BY id desc LIMIT 20
741
714
  The `reorder` method overrides the default scope order. For example:
742
715
 
743
716
  ```ruby
744
- class Post < ActiveRecord::Base
745
- ..
746
- ..
717
+ class Article < ActiveRecord::Base
747
718
  has_many :comments, -> { order('posted_at DESC') }
748
719
  end
749
720
 
750
- Post.find(10).comments.reorder('name')
721
+ Article.find(10).comments.reorder('name')
751
722
  ```
752
723
 
753
724
  The SQL that would be executed:
754
725
 
755
726
  ```sql
756
- SELECT * FROM posts WHERE id = 10
757
- SELECT * FROM comments WHERE post_id = 10 ORDER BY name
727
+ SELECT * FROM articles WHERE id = 10
728
+ SELECT * FROM comments WHERE article_id = 10 ORDER BY name
758
729
  ```
759
730
 
760
731
  In case the `reorder` clause is not used, the SQL executed would be:
761
732
 
762
733
  ```sql
763
- SELECT * FROM posts WHERE id = 10
764
- SELECT * FROM comments WHERE post_id = 10 ORDER BY posted_at DESC
734
+ SELECT * FROM articles WHERE id = 10
735
+ SELECT * FROM comments WHERE article_id = 10 ORDER BY posted_at DESC
765
736
  ```
766
737
 
767
738
  ### `reverse_order`
@@ -797,25 +768,25 @@ This method accepts **no** arguments.
797
768
  The `rewhere` method overrides an existing, named where condition. For example:
798
769
 
799
770
  ```ruby
800
- Post.where(trashed: true).rewhere(trashed: false)
771
+ Article.where(trashed: true).rewhere(trashed: false)
801
772
  ```
802
773
 
803
774
  The SQL that would be executed:
804
775
 
805
776
  ```sql
806
- SELECT * FROM posts WHERE `trashed` = 0
777
+ SELECT * FROM articles WHERE `trashed` = 0
807
778
  ```
808
779
 
809
780
  In case the `rewhere` clause is not used,
810
781
 
811
782
  ```ruby
812
- Post.where(trashed: true).where(trashed: false)
783
+ Article.where(trashed: true).where(trashed: false)
813
784
  ```
814
785
 
815
786
  the SQL executed would be:
816
787
 
817
788
  ```sql
818
- SELECT * FROM posts WHERE `trashed` = 1 AND `trashed` = 0
789
+ SELECT * FROM articles WHERE `trashed` = 1 AND `trashed` = 0
819
790
  ```
820
791
 
821
792
  Null Relation
@@ -824,21 +795,21 @@ Null Relation
824
795
  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
796
 
826
797
  ```ruby
827
- Post.none # returns an empty Relation and fires no queries.
798
+ Article.none # returns an empty Relation and fires no queries.
828
799
  ```
829
800
 
830
801
  ```ruby
831
- # The visible_posts method below is expected to return a Relation.
832
- @posts = current_user.visible_posts.where(name: params[:name])
802
+ # The visible_articles method below is expected to return a Relation.
803
+ @articles = current_user.visible_articles.where(name: params[:name])
833
804
 
834
- def visible_posts
805
+ def visible_articles
835
806
  case role
836
807
  when 'Country Manager'
837
- Post.where(country: country)
808
+ Article.where(country: country)
838
809
  when 'Reviewer'
839
- Post.published
810
+ Article.published
840
811
  when 'Bad User'
841
- Post.none # => returning [] or nil breaks the caller code in this case
812
+ Article.none # => returning [] or nil breaks the caller code in this case
842
813
  end
843
814
  end
844
815
  ```
@@ -963,23 +934,23 @@ SELECT clients.* FROM clients LEFT OUTER JOIN addresses ON addresses.client_id =
963
934
 
964
935
  WARNING: This method only works with `INNER JOIN`.
965
936
 
966
- 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.
937
+ 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
938
 
968
- For example, consider the following `Category`, `Post`, `Comment`, `Guest` and `Tag` models:
939
+ For example, consider the following `Category`, `Article`, `Comment`, `Guest` and `Tag` models:
969
940
 
970
941
  ```ruby
971
942
  class Category < ActiveRecord::Base
972
- has_many :posts
943
+ has_many :articles
973
944
  end
974
945
 
975
- class Post < ActiveRecord::Base
946
+ class Article < ActiveRecord::Base
976
947
  belongs_to :category
977
948
  has_many :comments
978
949
  has_many :tags
979
950
  end
980
951
 
981
952
  class Comment < ActiveRecord::Base
982
- belongs_to :post
953
+ belongs_to :article
983
954
  has_one :guest
984
955
  end
985
956
 
@@ -988,7 +959,7 @@ class Guest < ActiveRecord::Base
988
959
  end
989
960
 
990
961
  class Tag < ActiveRecord::Base
991
- belongs_to :post
962
+ belongs_to :article
992
963
  end
993
964
  ```
994
965
 
@@ -997,64 +968,64 @@ Now all of the following will produce the expected join queries using `INNER JOI
997
968
  #### Joining a Single Association
998
969
 
999
970
  ```ruby
1000
- Category.joins(:posts)
971
+ Category.joins(:articles)
1001
972
  ```
1002
973
 
1003
974
  This produces:
1004
975
 
1005
976
  ```sql
1006
977
  SELECT categories.* FROM categories
1007
- INNER JOIN posts ON posts.category_id = categories.id
978
+ INNER JOIN articles ON articles.category_id = categories.id
1008
979
  ```
1009
980
 
1010
- 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).uniq`.
981
+ 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
982
 
1012
983
  #### Joining Multiple Associations
1013
984
 
1014
985
  ```ruby
1015
- Post.joins(:category, :comments)
986
+ Article.joins(:category, :comments)
1016
987
  ```
1017
988
 
1018
989
  This produces:
1019
990
 
1020
991
  ```sql
1021
- SELECT posts.* FROM posts
1022
- INNER JOIN categories ON posts.category_id = categories.id
1023
- INNER JOIN comments ON comments.post_id = posts.id
992
+ SELECT articles.* FROM articles
993
+ INNER JOIN categories ON articles.category_id = categories.id
994
+ INNER JOIN comments ON comments.article_id = articles.id
1024
995
  ```
1025
996
 
1026
- 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.
997
+ 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
998
 
1028
999
  #### Joining Nested Associations (Single Level)
1029
1000
 
1030
1001
  ```ruby
1031
- Post.joins(comments: :guest)
1002
+ Article.joins(comments: :guest)
1032
1003
  ```
1033
1004
 
1034
1005
  This produces:
1035
1006
 
1036
1007
  ```sql
1037
- SELECT posts.* FROM posts
1038
- INNER JOIN comments ON comments.post_id = posts.id
1008
+ SELECT articles.* FROM articles
1009
+ INNER JOIN comments ON comments.article_id = articles.id
1039
1010
  INNER JOIN guests ON guests.comment_id = comments.id
1040
1011
  ```
1041
1012
 
1042
- Or, in English: "return all posts that have a comment made by a guest."
1013
+ Or, in English: "return all articles that have a comment made by a guest."
1043
1014
 
1044
1015
  #### Joining Nested Associations (Multiple Level)
1045
1016
 
1046
1017
  ```ruby
1047
- Category.joins(posts: [{ comments: :guest }, :tags])
1018
+ Category.joins(articles: [{ comments: :guest }, :tags])
1048
1019
  ```
1049
1020
 
1050
1021
  This produces:
1051
1022
 
1052
1023
  ```sql
1053
1024
  SELECT categories.* FROM categories
1054
- INNER JOIN posts ON posts.category_id = categories.id
1055
- INNER JOIN comments ON comments.post_id = posts.id
1025
+ INNER JOIN articles ON articles.category_id = categories.id
1026
+ INNER JOIN comments ON comments.article_id = articles.id
1056
1027
  INNER JOIN guests ON guests.comment_id = comments.id
1057
- INNER JOIN tags ON tags.post_id = posts.id
1028
+ INNER JOIN tags ON tags.article_id = articles.id
1058
1029
  ```
1059
1030
 
1060
1031
  ### Specifying Conditions on the Joined Tables
@@ -1123,18 +1094,18 @@ Active Record lets you eager load any number of associations with a single `Mode
1123
1094
  #### Array of Multiple Associations
1124
1095
 
1125
1096
  ```ruby
1126
- Post.includes(:category, :comments)
1097
+ Article.includes(:category, :comments)
1127
1098
  ```
1128
1099
 
1129
- This loads all the posts and the associated category and comments for each post.
1100
+ This loads all the articles and the associated category and comments for each article.
1130
1101
 
1131
1102
  #### Nested Associations Hash
1132
1103
 
1133
1104
  ```ruby
1134
- Category.includes(posts: [{ comments: :guest }, :tags]).find(1)
1105
+ Category.includes(articles: [{ comments: :guest }, :tags]).find(1)
1135
1106
  ```
1136
1107
 
1137
- 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.
1108
+ 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
1109
 
1139
1110
  ### Specifying Conditions on Eager Loaded Associations
1140
1111
 
@@ -1143,29 +1114,30 @@ Even though Active Record lets you specify conditions on the eager loaded associ
1143
1114
  However if you must do this, you may use `where` as you would normally.
1144
1115
 
1145
1116
  ```ruby
1146
- Post.includes(:comments).where(comments: { visible: true })
1117
+ Article.includes(:comments).where(comments: { visible: true })
1147
1118
  ```
1148
1119
 
1149
1120
  This would generate a query which contains a `LEFT OUTER JOIN` whereas the
1150
1121
  `joins` method would generate one using the `INNER JOIN` function instead.
1151
1122
 
1152
1123
  ```ruby
1153
- 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)
1124
+ 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
1125
  ```
1155
1126
 
1156
- If there was no `where` condition, this would generate the normal set of two
1157
- queries.
1127
+ If there was no `where` condition, this would generate the normal set of two queries.
1158
1128
 
1159
1129
  NOTE: Using `where` like this will only work when you pass it a Hash. For
1160
1130
  SQL-fragments you need use `references` to force joined tables:
1161
1131
 
1162
1132
  ```ruby
1163
- Post.includes(:comments).where("comments.visible = true").references(:comments)
1133
+ Article.includes(:comments).where("comments.visible = true").references(:comments)
1164
1134
  ```
1165
1135
 
1166
- If, in the case of this `includes` query, there were no comments for any posts,
1167
- all the posts would still be loaded. By using `joins` (an INNER JOIN), the join
1168
- conditions **must** match, otherwise no records will be returned.
1136
+ If, in the case of this `includes` query, there were no comments for any
1137
+ articles, all the articles would still be loaded. By using `joins` (an INNER
1138
+ JOIN), the join conditions **must** match, otherwise no records will be
1139
+ returned.
1140
+
1169
1141
 
1170
1142
 
1171
1143
  Scopes
@@ -1176,7 +1148,7 @@ Scoping allows you to specify commonly-used queries which can be referenced as m
1176
1148
  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
1149
 
1178
1150
  ```ruby
1179
- class Post < ActiveRecord::Base
1151
+ class Article < ActiveRecord::Base
1180
1152
  scope :published, -> { where(published: true) }
1181
1153
  end
1182
1154
  ```
@@ -1184,7 +1156,7 @@ end
1184
1156
  This is exactly the same as defining a class method, and which you use is a matter of personal preference:
1185
1157
 
1186
1158
  ```ruby
1187
- class Post < ActiveRecord::Base
1159
+ class Article < ActiveRecord::Base
1188
1160
  def self.published
1189
1161
  where(published: true)
1190
1162
  end
@@ -1194,7 +1166,7 @@ end
1194
1166
  Scopes are also chainable within scopes:
1195
1167
 
1196
1168
  ```ruby
1197
- class Post < ActiveRecord::Base
1169
+ class Article < ActiveRecord::Base
1198
1170
  scope :published, -> { where(published: true) }
1199
1171
  scope :published_and_commented, -> { published.where("comments_count > 0") }
1200
1172
  end
@@ -1203,14 +1175,14 @@ end
1203
1175
  To call this `published` scope we can call it on either the class:
1204
1176
 
1205
1177
  ```ruby
1206
- Post.published # => [published posts]
1178
+ Article.published # => [published articles]
1207
1179
  ```
1208
1180
 
1209
- Or on an association consisting of `Post` objects:
1181
+ Or on an association consisting of `Article` objects:
1210
1182
 
1211
1183
  ```ruby
1212
1184
  category = Category.first
1213
- category.posts.published # => [published posts belonging to this category]
1185
+ category.articles.published # => [published articles belonging to this category]
1214
1186
  ```
1215
1187
 
1216
1188
  ### Passing in arguments
@@ -1218,7 +1190,7 @@ category.posts.published # => [published posts belonging to this category]
1218
1190
  Your scope can take arguments:
1219
1191
 
1220
1192
  ```ruby
1221
- class Post < ActiveRecord::Base
1193
+ class Article < ActiveRecord::Base
1222
1194
  scope :created_before, ->(time) { where("created_at < ?", time) }
1223
1195
  end
1224
1196
  ```
@@ -1226,13 +1198,13 @@ end
1226
1198
  Call the scope as if it were a class method:
1227
1199
 
1228
1200
  ```ruby
1229
- Post.created_before(Time.zone.now)
1201
+ Article.created_before(Time.zone.now)
1230
1202
  ```
1231
1203
 
1232
1204
  However, this is just duplicating the functionality that would be provided to you by a class method.
1233
1205
 
1234
1206
  ```ruby
1235
- class Post < ActiveRecord::Base
1207
+ class Article < ActiveRecord::Base
1236
1208
  def self.created_before(time)
1237
1209
  where("created_at < ?", time)
1238
1210
  end
@@ -1242,7 +1214,36 @@ end
1242
1214
  Using a class method is the preferred way to accept arguments for scopes. These methods will still be accessible on the association objects:
1243
1215
 
1244
1216
  ```ruby
1245
- category.posts.created_before(time)
1217
+ category.articles.created_before(time)
1218
+ ```
1219
+
1220
+ ### Applying a default scope
1221
+
1222
+ If we wish for a scope to be applied across all queries to the model we can use the
1223
+ `default_scope` method within the model itself.
1224
+
1225
+ ```ruby
1226
+ class Client < ActiveRecord::Base
1227
+ default_scope { where("removed_at IS NULL") }
1228
+ end
1229
+ ```
1230
+
1231
+ When queries are executed on this model, the SQL query will now look something like
1232
+ this:
1233
+
1234
+ ```sql
1235
+ SELECT * FROM clients WHERE removed_at IS NULL
1236
+ ```
1237
+
1238
+ If you need to do more complex things with a default scope, you can alternatively
1239
+ define it as a class method:
1240
+
1241
+ ```ruby
1242
+ class Client < ActiveRecord::Base
1243
+ def self.default_scope
1244
+ # Should return an ActiveRecord::Relation.
1245
+ end
1246
+ end
1246
1247
  ```
1247
1248
 
1248
1249
  ### Merging of scopes
@@ -1298,36 +1299,6 @@ User.where(state: 'inactive')
1298
1299
  As you can see above the `default_scope` is being merged in both
1299
1300
  `scope` and `where` conditions.
1300
1301
 
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
1302
  ### Removing All Scoping
1332
1303
 
1333
1304
  If we wish to remove scoping for any reason we can use the `unscoped` method. This is
@@ -1470,6 +1441,11 @@ If you'd like to use your own SQL to find records in a table you can use `find_b
1470
1441
  Client.find_by_sql("SELECT * FROM clients
1471
1442
  INNER JOIN orders ON clients.id = orders.client_id
1472
1443
  ORDER BY clients.created_at desc")
1444
+ # => [
1445
+ #<Client id: 1, first_name: "Lucas" >,
1446
+ #<Client id: 2, first_name: "Jan" >,
1447
+ # ...
1448
+ ]
1473
1449
  ```
1474
1450
 
1475
1451
  `find_by_sql` provides you with a simple way of making custom calls to the database and retrieving instantiated objects.
@@ -1479,12 +1455,16 @@ Client.find_by_sql("SELECT * FROM clients
1479
1455
  `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
1456
 
1481
1457
  ```ruby
1482
- Client.connection.select_all("SELECT * FROM clients WHERE id = '1'")
1458
+ Client.connection.select_all("SELECT first_name, created_at FROM clients WHERE id = '1'")
1459
+ # => [
1460
+ {"first_name"=>"Rafael", "created_at"=>"2012-11-10 23:23:45.281189"},
1461
+ {"first_name"=>"Eileen", "created_at"=>"2013-12-09 11:22:35.221282"}
1462
+ ]
1483
1463
  ```
1484
1464
 
1485
1465
  ### `pluck`
1486
1466
 
1487
- `pluck` 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.
1467
+ `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
1468
 
1489
1469
  ```ruby
1490
1470
  Client.where(active: true).pluck(:id)
@@ -1606,20 +1586,20 @@ You can also use `any?` and `many?` to check for existence on a model or relatio
1606
1586
 
1607
1587
  ```ruby
1608
1588
  # via a model
1609
- Post.any?
1610
- Post.many?
1589
+ Article.any?
1590
+ Article.many?
1611
1591
 
1612
1592
  # via a named scope
1613
- Post.recent.any?
1614
- Post.recent.many?
1593
+ Article.recent.any?
1594
+ Article.recent.many?
1615
1595
 
1616
1596
  # via a relation
1617
- Post.where(published: true).any?
1618
- Post.where(published: true).many?
1597
+ Article.where(published: true).any?
1598
+ Article.where(published: true).many?
1619
1599
 
1620
1600
  # via an association
1621
- Post.first.categories.any?
1622
- Post.first.categories.many?
1601
+ Article.first.categories.any?
1602
+ Article.first.categories.many?
1623
1603
  ```
1624
1604
 
1625
1605
  Calculations
@@ -1709,19 +1689,26 @@ Running EXPLAIN
1709
1689
  You can run EXPLAIN on the queries triggered by relations. For example,
1710
1690
 
1711
1691
  ```ruby
1712
- User.where(id: 1).joins(:posts).explain
1692
+ User.where(id: 1).joins(:articles).explain
1713
1693
  ```
1714
1694
 
1715
1695
  may yield
1716
1696
 
1717
1697
  ```
1718
- EXPLAIN for: SELECT `users`.* FROM `users` INNER JOIN `posts` ON `posts`.`user_id` = `users`.`id` WHERE `users`.`id` = 1
1719
- +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+
1720
- | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
1721
- +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+
1722
- | 1 | SIMPLE | users | const | PRIMARY | PRIMARY | 4 | const | 1 | |
1723
- | 1 | SIMPLE | posts | ALL | NULL | NULL | NULL | NULL | 1 | Using where |
1724
- +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+
1698
+ EXPLAIN for: SELECT `users`.* FROM `users` INNER JOIN `articles` ON `articles`.`user_id` = `users`.`id` WHERE `users`.`id` = 1
1699
+ +----+-------------+----------+-------+---------------+
1700
+ | id | select_type | table | type | possible_keys |
1701
+ +----+-------------+----------+-------+---------------+
1702
+ | 1 | SIMPLE | users | const | PRIMARY |
1703
+ | 1 | SIMPLE | articles | ALL | NULL |
1704
+ +----+-------------+----------+-------+---------------+
1705
+ +---------+---------+-------+------+-------------+
1706
+ | key | key_len | ref | rows | Extra |
1707
+ +---------+---------+-------+------+-------------+
1708
+ | PRIMARY | 4 | const | 1 | |
1709
+ | NULL | NULL | NULL | 1 | Using where |
1710
+ +---------+---------+-------+------+-------------+
1711
+
1725
1712
  2 rows in set (0.00 sec)
1726
1713
  ```
1727
1714
 
@@ -1731,15 +1718,15 @@ Active Record performs a pretty printing that emulates the one of the database
1731
1718
  shells. So, the same query running with the PostgreSQL adapter would yield instead
1732
1719
 
1733
1720
  ```
1734
- EXPLAIN for: SELECT "users".* FROM "users" INNER JOIN "posts" ON "posts"."user_id" = "users"."id" WHERE "users"."id" = 1
1721
+ EXPLAIN for: SELECT "users".* FROM "users" INNER JOIN "articles" ON "articles"."user_id" = "users"."id" WHERE "users"."id" = 1
1735
1722
  QUERY PLAN
1736
1723
  ------------------------------------------------------------------------------
1737
1724
  Nested Loop Left Join (cost=0.00..37.24 rows=8 width=0)
1738
- Join Filter: (posts.user_id = users.id)
1725
+ Join Filter: (articles.user_id = users.id)
1739
1726
  -> Index Scan using users_pkey on users (cost=0.00..8.27 rows=1 width=4)
1740
1727
  Index Cond: (id = 1)
1741
- -> Seq Scan on posts (cost=0.00..28.88 rows=8 width=4)
1742
- Filter: (posts.user_id = 1)
1728
+ -> Seq Scan on articles (cost=0.00..28.88 rows=8 width=4)
1729
+ Filter: (articles.user_id = 1)
1743
1730
  (6 rows)
1744
1731
  ```
1745
1732
 
@@ -1748,26 +1735,39 @@ may need the results of previous ones. Because of that, `explain` actually
1748
1735
  executes the query, and then asks for the query plans. For example,
1749
1736
 
1750
1737
  ```ruby
1751
- User.where(id: 1).includes(:posts).explain
1738
+ User.where(id: 1).includes(:articles).explain
1752
1739
  ```
1753
1740
 
1754
1741
  yields
1755
1742
 
1756
1743
  ```
1757
1744
  EXPLAIN for: SELECT `users`.* FROM `users` WHERE `users`.`id` = 1
1758
- +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+
1759
- | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
1760
- +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+
1761
- | 1 | SIMPLE | users | const | PRIMARY | PRIMARY | 4 | const | 1 | |
1762
- +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+
1745
+ +----+-------------+-------+-------+---------------+
1746
+ | id | select_type | table | type | possible_keys |
1747
+ +----+-------------+-------+-------+---------------+
1748
+ | 1 | SIMPLE | users | const | PRIMARY |
1749
+ +----+-------------+-------+-------+---------------+
1750
+ +---------+---------+-------+------+-------+
1751
+ | key | key_len | ref | rows | Extra |
1752
+ +---------+---------+-------+------+-------+
1753
+ | PRIMARY | 4 | const | 1 | |
1754
+ +---------+---------+-------+------+-------+
1755
+
1763
1756
  1 row in set (0.00 sec)
1764
1757
 
1765
- EXPLAIN for: SELECT `posts`.* FROM `posts` WHERE `posts`.`user_id` IN (1)
1766
- +----+-------------+-------+------+---------------+------+---------+------+------+-------------+
1767
- | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
1768
- +----+-------------+-------+------+---------------+------+---------+------+------+-------------+
1769
- | 1 | SIMPLE | posts | ALL | NULL | NULL | NULL | NULL | 1 | Using where |
1770
- +----+-------------+-------+------+---------------+------+---------+------+------+-------------+
1758
+ EXPLAIN for: SELECT `articles`.* FROM `articles` WHERE `articles`.`user_id` IN (1)
1759
+ +----+-------------+----------+------+---------------+
1760
+ | id | select_type | table | type | possible_keys |
1761
+ +----+-------------+----------+------+---------------+
1762
+ | 1 | SIMPLE | articles | ALL | NULL |
1763
+ +----+-------------+----------+------+---------------+
1764
+ +------+---------+------+------+-------------+
1765
+ | key | key_len | ref | rows | Extra |
1766
+ +------+---------+------+------+-------------+
1767
+ | NULL | NULL | NULL | 1 | Using where |
1768
+ +------+---------+------+------+-------------+
1769
+
1770
+
1771
1771
  1 row in set (0.00 sec)
1772
1772
  ```
1773
1773