rails 4.1.16 → 4.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +12 -10
- data/guides/CHANGELOG.md +15 -100
- data/guides/Rakefile +5 -3
- data/guides/assets/javascripts/guides.js +6 -0
- data/guides/assets/stylesheets/main.css +4 -1
- data/guides/bug_report_templates/action_controller_master.rb +1 -0
- data/guides/rails_guides/helpers.rb +1 -1
- data/guides/rails_guides/levenshtein.rb +29 -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 +5 -6
- data/guides/source/4_2_release_notes.md +850 -0
- data/guides/source/_license.html.erb +1 -1
- data/guides/source/_welcome.html.erb +2 -8
- data/guides/source/action_controller_overview.md +81 -7
- data/guides/source/action_mailer_basics.md +91 -28
- data/guides/source/action_view_overview.md +148 -130
- data/guides/source/active_job_basics.md +318 -0
- data/guides/source/active_model_basics.md +371 -17
- data/guides/source/active_record_basics.md +19 -18
- 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 +263 -265
- data/guides/source/active_record_validations.md +20 -11
- data/guides/source/active_support_core_extensions.md +159 -72
- data/guides/source/active_support_instrumentation.md +10 -7
- data/guides/source/api_documentation_guidelines.md +62 -16
- data/guides/source/asset_pipeline.md +258 -63
- data/guides/source/association_basics.md +81 -74
- data/guides/source/caching_with_rails.md +32 -7
- data/guides/source/command_line.md +52 -30
- data/guides/source/configuring.md +132 -29
- data/guides/source/constant_autoloading_and_reloading.md +1297 -0
- data/guides/source/contributing_to_ruby_on_rails.md +192 -112
- 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 +182 -182
- data/guides/source/form_helpers.md +79 -56
- data/guides/source/generators.md +24 -11
- data/guides/source/getting_started.md +337 -198
- data/guides/source/i18n.md +108 -65
- data/guides/source/index.html.erb +1 -0
- data/guides/source/initialization.md +108 -61
- data/guides/source/layout.html.erb +1 -4
- data/guides/source/layouts_and_rendering.md +27 -25
- 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 -4
- data/guides/source/routing.md +98 -72
- data/guides/source/ruby_on_rails_guides_guidelines.md +11 -12
- data/guides/source/security.md +38 -32
- data/guides/source/testing.md +188 -117
- data/guides/source/upgrading_ruby_on_rails.md +254 -28
- data/guides/source/working_with_javascript_in_rails.md +18 -16
- data/guides/w3c_validator.rb +2 -0
- metadata +40 -96
- data/guides/bug_report_templates/generic_gem.rb +0 -15
- data/guides/bug_report_templates/generic_master.rb +0 -26
- 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
@@ -101,13 +101,13 @@ class CreateOrders < ActiveRecord::Migration
|
|
101
101
|
def change
|
102
102
|
create_table :customers do |t|
|
103
103
|
t.string :name
|
104
|
-
t.timestamps
|
104
|
+
t.timestamps null: false
|
105
105
|
end
|
106
106
|
|
107
107
|
create_table :orders do |t|
|
108
|
-
t.belongs_to :customer
|
108
|
+
t.belongs_to :customer, index: true
|
109
109
|
t.datetime :order_date
|
110
|
-
t.timestamps
|
110
|
+
t.timestamps null: false
|
111
111
|
end
|
112
112
|
end
|
113
113
|
end
|
@@ -132,13 +132,13 @@ class CreateSuppliers < ActiveRecord::Migration
|
|
132
132
|
def change
|
133
133
|
create_table :suppliers do |t|
|
134
134
|
t.string :name
|
135
|
-
t.timestamps
|
135
|
+
t.timestamps null: false
|
136
136
|
end
|
137
137
|
|
138
138
|
create_table :accounts do |t|
|
139
|
-
t.belongs_to :supplier
|
139
|
+
t.belongs_to :supplier, index: true
|
140
140
|
t.string :account_number
|
141
|
-
t.timestamps
|
141
|
+
t.timestamps null: false
|
142
142
|
end
|
143
143
|
end
|
144
144
|
end
|
@@ -165,13 +165,13 @@ class CreateCustomers < ActiveRecord::Migration
|
|
165
165
|
def change
|
166
166
|
create_table :customers do |t|
|
167
167
|
t.string :name
|
168
|
-
t.timestamps
|
168
|
+
t.timestamps null: false
|
169
169
|
end
|
170
170
|
|
171
171
|
create_table :orders do |t|
|
172
|
-
t.belongs_to :customer
|
172
|
+
t.belongs_to :customer, index:true
|
173
173
|
t.datetime :order_date
|
174
|
-
t.timestamps
|
174
|
+
t.timestamps null: false
|
175
175
|
end
|
176
176
|
end
|
177
177
|
end
|
@@ -207,19 +207,19 @@ class CreateAppointments < ActiveRecord::Migration
|
|
207
207
|
def change
|
208
208
|
create_table :physicians do |t|
|
209
209
|
t.string :name
|
210
|
-
t.timestamps
|
210
|
+
t.timestamps null: false
|
211
211
|
end
|
212
212
|
|
213
213
|
create_table :patients do |t|
|
214
214
|
t.string :name
|
215
|
-
t.timestamps
|
215
|
+
t.timestamps null: false
|
216
216
|
end
|
217
217
|
|
218
218
|
create_table :appointments do |t|
|
219
|
-
t.belongs_to :physician
|
220
|
-
t.belongs_to :patient
|
219
|
+
t.belongs_to :physician, index: true
|
220
|
+
t.belongs_to :patient, index: true
|
221
221
|
t.datetime :appointment_date
|
222
|
-
t.timestamps
|
222
|
+
t.timestamps null: false
|
223
223
|
end
|
224
224
|
end
|
225
225
|
end
|
@@ -291,19 +291,19 @@ class CreateAccountHistories < ActiveRecord::Migration
|
|
291
291
|
def change
|
292
292
|
create_table :suppliers do |t|
|
293
293
|
t.string :name
|
294
|
-
t.timestamps
|
294
|
+
t.timestamps null: false
|
295
295
|
end
|
296
296
|
|
297
297
|
create_table :accounts do |t|
|
298
|
-
t.belongs_to :supplier
|
298
|
+
t.belongs_to :supplier, index: true
|
299
299
|
t.string :account_number
|
300
|
-
t.timestamps
|
300
|
+
t.timestamps null: false
|
301
301
|
end
|
302
302
|
|
303
303
|
create_table :account_histories do |t|
|
304
|
-
t.belongs_to :account
|
304
|
+
t.belongs_to :account, index: true
|
305
305
|
t.integer :credit_rating
|
306
|
-
t.timestamps
|
306
|
+
t.timestamps null: false
|
307
307
|
end
|
308
308
|
end
|
309
309
|
end
|
@@ -332,17 +332,17 @@ class CreateAssembliesAndParts < ActiveRecord::Migration
|
|
332
332
|
def change
|
333
333
|
create_table :assemblies do |t|
|
334
334
|
t.string :name
|
335
|
-
t.timestamps
|
335
|
+
t.timestamps null: false
|
336
336
|
end
|
337
337
|
|
338
338
|
create_table :parts do |t|
|
339
339
|
t.string :part_number
|
340
|
-
t.timestamps
|
340
|
+
t.timestamps null: false
|
341
341
|
end
|
342
342
|
|
343
343
|
create_table :assemblies_parts, id: false do |t|
|
344
|
-
t.belongs_to :assembly
|
345
|
-
t.belongs_to :part
|
344
|
+
t.belongs_to :assembly, index: true
|
345
|
+
t.belongs_to :part, index: true
|
346
346
|
end
|
347
347
|
end
|
348
348
|
end
|
@@ -371,14 +371,16 @@ class CreateSuppliers < ActiveRecord::Migration
|
|
371
371
|
def change
|
372
372
|
create_table :suppliers do |t|
|
373
373
|
t.string :name
|
374
|
-
t.timestamps
|
374
|
+
t.timestamps null: false
|
375
375
|
end
|
376
376
|
|
377
377
|
create_table :accounts do |t|
|
378
378
|
t.integer :supplier_id
|
379
379
|
t.string :account_number
|
380
|
-
t.timestamps
|
380
|
+
t.timestamps null: false
|
381
381
|
end
|
382
|
+
|
383
|
+
add_index :accounts, :supplier_id
|
382
384
|
end
|
383
385
|
end
|
384
386
|
```
|
@@ -453,8 +455,10 @@ class CreatePictures < ActiveRecord::Migration
|
|
453
455
|
t.string :name
|
454
456
|
t.integer :imageable_id
|
455
457
|
t.string :imageable_type
|
456
|
-
t.timestamps
|
458
|
+
t.timestamps null: false
|
457
459
|
end
|
460
|
+
|
461
|
+
add_index :pictures, :imageable_id
|
458
462
|
end
|
459
463
|
end
|
460
464
|
```
|
@@ -466,8 +470,8 @@ class CreatePictures < ActiveRecord::Migration
|
|
466
470
|
def change
|
467
471
|
create_table :pictures do |t|
|
468
472
|
t.string :name
|
469
|
-
t.references :imageable, polymorphic: true
|
470
|
-
t.timestamps
|
473
|
+
t.references :imageable, polymorphic: true, index: true
|
474
|
+
t.timestamps null: false
|
471
475
|
end
|
472
476
|
end
|
473
477
|
end
|
@@ -496,8 +500,8 @@ In your migrations/schema, you will add a references column to the model itself.
|
|
496
500
|
class CreateEmployees < ActiveRecord::Migration
|
497
501
|
def change
|
498
502
|
create_table :employees do |t|
|
499
|
-
t.references :manager
|
500
|
-
t.timestamps
|
503
|
+
t.references :manager, index: true
|
504
|
+
t.timestamps null: false
|
501
505
|
end
|
502
506
|
end
|
503
507
|
end
|
@@ -561,6 +565,8 @@ class CreateOrders < ActiveRecord::Migration
|
|
561
565
|
t.string :order_number
|
562
566
|
t.integer :customer_id
|
563
567
|
end
|
568
|
+
|
569
|
+
add_index :orders, :customer_id
|
564
570
|
end
|
565
571
|
end
|
566
572
|
```
|
@@ -571,7 +577,7 @@ If you create an association some time after you build the underlying model, you
|
|
571
577
|
|
572
578
|
If you create a `has_and_belongs_to_many` association, you need to explicitly create the joining table. Unless the name of the join table is explicitly specified by using the `:join_table` option, Active Record creates the name by using the lexical order of the class names. So a join between customer and order models will give the default join table name of "customers_orders" because "c" outranks "o" in lexical ordering.
|
573
579
|
|
574
|
-
WARNING: The precedence between model names is calculated using the `<` operator for `String`. This means that if the strings are of different lengths, and the strings are equal when compared up to the shortest length, then the longer string is considered of higher lexical precedence than the shorter one. For example, one would expect the tables "
|
580
|
+
WARNING: The precedence between model names is calculated using the `<` operator for `String`. This means that if the strings are of different lengths, and the strings are equal when compared up to the shortest length, then the longer string is considered of higher lexical precedence than the shorter one. For example, one would expect the tables "paper_boxes" and "papers" to generate a join table name of "papers_paper_boxes" because of the length of the name "paper_boxes", but it in fact generates a join table name of "paper_boxes_papers" (because the underscore '_' is lexicographically _less_ than 's' in common encodings).
|
575
581
|
|
576
582
|
Whatever the name, you must manually generate the join table with an appropriate migration. For example, consider these associations:
|
577
583
|
|
@@ -594,6 +600,9 @@ class CreateAssembliesPartsJoinTable < ActiveRecord::Migration
|
|
594
600
|
t.integer :assembly_id
|
595
601
|
t.integer :part_id
|
596
602
|
end
|
603
|
+
|
604
|
+
add_index :assemblies_parts, :assembly_id
|
605
|
+
add_index :assemblies_parts, :part_id
|
597
606
|
end
|
598
607
|
end
|
599
608
|
```
|
@@ -747,7 +756,7 @@ class Order < ActiveRecord::Base
|
|
747
756
|
end
|
748
757
|
```
|
749
758
|
|
750
|
-
Each instance of the
|
759
|
+
Each instance of the `Order` model will have these methods:
|
751
760
|
|
752
761
|
```ruby
|
753
762
|
customer
|
@@ -1131,7 +1140,7 @@ The `has_one` association supports these options:
|
|
1131
1140
|
|
1132
1141
|
##### `:as`
|
1133
1142
|
|
1134
|
-
Setting the `:as` option indicates that this is a polymorphic association. Polymorphic associations were discussed in detail
|
1143
|
+
Setting the `:as` option indicates that this is a polymorphic association. Polymorphic associations were discussed in detail [earlier in this guide](#polymorphic-associations).
|
1135
1144
|
|
1136
1145
|
##### `:autosave`
|
1137
1146
|
|
@@ -1203,7 +1212,7 @@ The `:source_type` option specifies the source association type for a `has_one :
|
|
1203
1212
|
|
1204
1213
|
##### `:through`
|
1205
1214
|
|
1206
|
-
The `:through` option specifies a join model through which to perform the query. `has_one :through` associations were discussed in detail
|
1215
|
+
The `:through` option specifies a join model through which to perform the query. `has_one :through` associations were discussed in detail [earlier in this guide](#the-has-one-through-association).
|
1207
1216
|
|
1208
1217
|
##### `:validate`
|
1209
1218
|
|
@@ -1312,9 +1321,9 @@ When you declare a `has_many` association, the declaring class automatically gai
|
|
1312
1321
|
* `collection<<(object, ...)`
|
1313
1322
|
* `collection.delete(object, ...)`
|
1314
1323
|
* `collection.destroy(object, ...)`
|
1315
|
-
* `collection=objects`
|
1324
|
+
* `collection=(objects)`
|
1316
1325
|
* `collection_singular_ids`
|
1317
|
-
* `collection_singular_ids=ids`
|
1326
|
+
* `collection_singular_ids=(ids)`
|
1318
1327
|
* `collection.clear`
|
1319
1328
|
* `collection.empty?`
|
1320
1329
|
* `collection.size`
|
@@ -1333,16 +1342,16 @@ class Customer < ActiveRecord::Base
|
|
1333
1342
|
end
|
1334
1343
|
```
|
1335
1344
|
|
1336
|
-
Each instance of the
|
1345
|
+
Each instance of the `Customer` model will have these methods:
|
1337
1346
|
|
1338
1347
|
```ruby
|
1339
1348
|
orders(force_reload = false)
|
1340
1349
|
orders<<(object, ...)
|
1341
1350
|
orders.delete(object, ...)
|
1342
1351
|
orders.destroy(object, ...)
|
1343
|
-
orders=objects
|
1352
|
+
orders=(objects)
|
1344
1353
|
order_ids
|
1345
|
-
order_ids=ids
|
1354
|
+
order_ids=(ids)
|
1346
1355
|
orders.clear
|
1347
1356
|
orders.empty?
|
1348
1357
|
orders.size
|
@@ -1390,7 +1399,7 @@ The `collection.destroy` method removes one or more objects from the collection
|
|
1390
1399
|
|
1391
1400
|
WARNING: Objects will _always_ be removed from the database, ignoring the `:dependent` option.
|
1392
1401
|
|
1393
|
-
##### `collection=objects`
|
1402
|
+
##### `collection=(objects)`
|
1394
1403
|
|
1395
1404
|
The `collection=` method makes the collection contain only the supplied objects, by adding and deleting as appropriate.
|
1396
1405
|
|
@@ -1402,7 +1411,7 @@ The `collection_singular_ids` method returns an array of the ids of the objects
|
|
1402
1411
|
@order_ids = @customer.order_ids
|
1403
1412
|
```
|
1404
1413
|
|
1405
|
-
##### `collection_singular_ids=ids`
|
1414
|
+
##### `collection_singular_ids=(ids)`
|
1406
1415
|
|
1407
1416
|
The `collection_singular_ids=` method makes the collection contain only the objects identified by the supplied primary key values, by adding and deleting as appropriate.
|
1408
1417
|
|
@@ -1497,7 +1506,7 @@ The `has_many` association supports these options:
|
|
1497
1506
|
|
1498
1507
|
##### `:as`
|
1499
1508
|
|
1500
|
-
Setting the `:as` option indicates that this is a polymorphic association, as discussed
|
1509
|
+
Setting the `:as` option indicates that this is a polymorphic association, as discussed [earlier in this guide](#polymorphic-associations).
|
1501
1510
|
|
1502
1511
|
##### `:autosave`
|
1503
1512
|
|
@@ -1523,8 +1532,6 @@ Controls what happens to the associated objects when their owner is destroyed:
|
|
1523
1532
|
* `:restrict_with_exception` causes an exception to be raised if there are any associated records
|
1524
1533
|
* `:restrict_with_error` causes an error to be added to the owner if there are any associated objects
|
1525
1534
|
|
1526
|
-
NOTE: This option is ignored when you use the `:through` option on the association.
|
1527
|
-
|
1528
1535
|
##### `:foreign_key`
|
1529
1536
|
|
1530
1537
|
By convention, Rails assumes that the column used to hold the foreign key on the other model is the name of this model with the suffix `_id` added. The `:foreign_key` option lets you set the name of the foreign key directly:
|
@@ -1579,7 +1586,7 @@ The `:source_type` option specifies the source association type for a `has_many
|
|
1579
1586
|
|
1580
1587
|
##### `:through`
|
1581
1588
|
|
1582
|
-
The `:through` option specifies a join model through which to perform the query. `has_many :through` associations provide a way to implement many-to-many relationships, as discussed
|
1589
|
+
The `:through` option specifies a join model through which to perform the query. `has_many :through` associations provide a way to implement many-to-many relationships, as discussed [earlier in this guide](#the-has-many-through-association).
|
1583
1590
|
|
1584
1591
|
##### `:validate`
|
1585
1592
|
|
@@ -1632,7 +1639,7 @@ If you use a hash-style `where` option, then record creation via this associatio
|
|
1632
1639
|
|
1633
1640
|
##### `extending`
|
1634
1641
|
|
1635
|
-
The `extending` method specifies a named module to extend the association proxy. Association extensions are discussed in detail
|
1642
|
+
The `extending` method specifies a named module to extend the association proxy. Association extensions are discussed in detail [later in this guide](#association-extensions).
|
1636
1643
|
|
1637
1644
|
##### `group`
|
1638
1645
|
|
@@ -1725,58 +1732,58 @@ mostly useful together with the `:through` option.
|
|
1725
1732
|
```ruby
|
1726
1733
|
class Person < ActiveRecord::Base
|
1727
1734
|
has_many :readings
|
1728
|
-
has_many :
|
1735
|
+
has_many :articles, through: :readings
|
1729
1736
|
end
|
1730
1737
|
|
1731
1738
|
person = Person.create(name: 'John')
|
1732
|
-
|
1733
|
-
person.
|
1734
|
-
person.
|
1735
|
-
person.
|
1736
|
-
Reading.all.inspect # => [#<Reading id: 12, person_id: 5,
|
1739
|
+
article = Article.create(name: 'a1')
|
1740
|
+
person.articles << article
|
1741
|
+
person.articles << article
|
1742
|
+
person.articles.inspect # => [#<Article id: 5, name: "a1">, #<Article id: 5, name: "a1">]
|
1743
|
+
Reading.all.inspect # => [#<Reading id: 12, person_id: 5, article_id: 5>, #<Reading id: 13, person_id: 5, article_id: 5>]
|
1737
1744
|
```
|
1738
1745
|
|
1739
|
-
In the above case there are two readings and `person.
|
1740
|
-
them even though these records are pointing to the same
|
1746
|
+
In the above case there are two readings and `person.articles` brings out both of
|
1747
|
+
them even though these records are pointing to the same article.
|
1741
1748
|
|
1742
1749
|
Now let's set `distinct`:
|
1743
1750
|
|
1744
1751
|
```ruby
|
1745
1752
|
class Person
|
1746
1753
|
has_many :readings
|
1747
|
-
has_many :
|
1754
|
+
has_many :articles, -> { distinct }, through: :readings
|
1748
1755
|
end
|
1749
1756
|
|
1750
1757
|
person = Person.create(name: 'Honda')
|
1751
|
-
|
1752
|
-
person.
|
1753
|
-
person.
|
1754
|
-
person.
|
1755
|
-
Reading.all.inspect # => [#<Reading id: 16, person_id: 7,
|
1758
|
+
article = Article.create(name: 'a1')
|
1759
|
+
person.articles << article
|
1760
|
+
person.articles << article
|
1761
|
+
person.articles.inspect # => [#<Article id: 7, name: "a1">]
|
1762
|
+
Reading.all.inspect # => [#<Reading id: 16, person_id: 7, article_id: 7>, #<Reading id: 17, person_id: 7, article_id: 7>]
|
1756
1763
|
```
|
1757
1764
|
|
1758
|
-
In the above case there are still two readings. However `person.
|
1759
|
-
only one
|
1765
|
+
In the above case there are still two readings. However `person.articles` shows
|
1766
|
+
only one article because the collection loads only unique records.
|
1760
1767
|
|
1761
1768
|
If you want to make sure that, upon insertion, all of the records in the
|
1762
1769
|
persisted association are distinct (so that you can be sure that when you
|
1763
1770
|
inspect the association that you will never find duplicate records), you should
|
1764
1771
|
add a unique index on the table itself. For example, if you have a table named
|
1765
|
-
`
|
1772
|
+
`person_articles` and you want to make sure all the articles are unique, you could
|
1766
1773
|
add the following in a migration:
|
1767
1774
|
|
1768
1775
|
```ruby
|
1769
|
-
add_index :
|
1776
|
+
add_index :person_articles, :article, unique: true
|
1770
1777
|
```
|
1771
1778
|
|
1772
1779
|
Note that checking for uniqueness using something like `include?` is subject
|
1773
1780
|
to race conditions. Do not attempt to use `include?` to enforce distinctness
|
1774
|
-
in an association. For instance, using the
|
1781
|
+
in an association. For instance, using the article example from above, the
|
1775
1782
|
following code would be racy because multiple users could be attempting this
|
1776
1783
|
at the same time:
|
1777
1784
|
|
1778
1785
|
```ruby
|
1779
|
-
person.
|
1786
|
+
person.articles << article unless person.articles.include?(article)
|
1780
1787
|
```
|
1781
1788
|
|
1782
1789
|
#### When are Objects Saved?
|
@@ -1801,9 +1808,9 @@ When you declare a `has_and_belongs_to_many` association, the declaring class au
|
|
1801
1808
|
* `collection<<(object, ...)`
|
1802
1809
|
* `collection.delete(object, ...)`
|
1803
1810
|
* `collection.destroy(object, ...)`
|
1804
|
-
* `collection=objects`
|
1811
|
+
* `collection=(objects)`
|
1805
1812
|
* `collection_singular_ids`
|
1806
|
-
* `collection_singular_ids=ids`
|
1813
|
+
* `collection_singular_ids=(ids)`
|
1807
1814
|
* `collection.clear`
|
1808
1815
|
* `collection.empty?`
|
1809
1816
|
* `collection.size`
|
@@ -1822,16 +1829,16 @@ class Part < ActiveRecord::Base
|
|
1822
1829
|
end
|
1823
1830
|
```
|
1824
1831
|
|
1825
|
-
Each instance of the
|
1832
|
+
Each instance of the `Part` model will have these methods:
|
1826
1833
|
|
1827
1834
|
```ruby
|
1828
1835
|
assemblies(force_reload = false)
|
1829
1836
|
assemblies<<(object, ...)
|
1830
1837
|
assemblies.delete(object, ...)
|
1831
1838
|
assemblies.destroy(object, ...)
|
1832
|
-
assemblies=objects
|
1839
|
+
assemblies=(objects)
|
1833
1840
|
assembly_ids
|
1834
|
-
assembly_ids=ids
|
1841
|
+
assembly_ids=(ids)
|
1835
1842
|
assemblies.clear
|
1836
1843
|
assemblies.empty?
|
1837
1844
|
assemblies.size
|
@@ -1886,7 +1893,7 @@ The `collection.destroy` method removes one or more objects from the collection
|
|
1886
1893
|
@part.assemblies.destroy(@assembly1)
|
1887
1894
|
```
|
1888
1895
|
|
1889
|
-
##### `collection=objects`
|
1896
|
+
##### `collection=(objects)`
|
1890
1897
|
|
1891
1898
|
The `collection=` method makes the collection contain only the supplied objects, by adding and deleting as appropriate.
|
1892
1899
|
|
@@ -1898,7 +1905,7 @@ The `collection_singular_ids` method returns an array of the ids of the objects
|
|
1898
1905
|
@assembly_ids = @part.assembly_ids
|
1899
1906
|
```
|
1900
1907
|
|
1901
|
-
##### `collection_singular_ids=ids`
|
1908
|
+
##### `collection_singular_ids=(ids)`
|
1902
1909
|
|
1903
1910
|
The `collection_singular_ids=` method makes the collection contain only the objects identified by the supplied primary key values, by adding and deleting as appropriate.
|
1904
1911
|
|
@@ -2082,7 +2089,7 @@ If you use a hash-style `where`, then record creation via this association will
|
|
2082
2089
|
|
2083
2090
|
##### `extending`
|
2084
2091
|
|
2085
|
-
The `extending` method specifies a named module to extend the association proxy. Association extensions are discussed in detail
|
2092
|
+
The `extending` method specifies a named module to extend the association proxy. Association extensions are discussed in detail [later in this guide](#association-extensions).
|
2086
2093
|
|
2087
2094
|
##### `group`
|
2088
2095
|
|
@@ -28,15 +28,15 @@ config.action_controller.perform_caching = true
|
|
28
28
|
|
29
29
|
### Page Caching
|
30
30
|
|
31
|
-
Page caching is a Rails mechanism which allows the request for a generated page to be fulfilled by the webserver (i.e. Apache or
|
31
|
+
Page caching is a Rails mechanism which allows the request for a generated page to be fulfilled by the webserver (i.e. Apache or NGINX), without ever having to go through the Rails stack at all. Obviously, this is super-fast. Unfortunately, it can't be applied to every situation (such as pages that need authentication) and since the webserver is literally just serving a file from the filesystem, cache expiration is an issue that needs to be dealt with.
|
32
32
|
|
33
|
-
INFO: Page Caching has been removed from Rails 4. See the [actionpack-page_caching gem](https://github.com/rails/actionpack-page_caching). See [DHH's key-based cache expiration overview](http://
|
33
|
+
INFO: Page Caching has been removed from Rails 4. See the [actionpack-page_caching gem](https://github.com/rails/actionpack-page_caching). See [DHH's key-based cache expiration overview](http://signalvnoise.com/posts/3113-how-key-based-cache-expiration-works) for the newly-preferred method.
|
34
34
|
|
35
35
|
### Action Caching
|
36
36
|
|
37
37
|
Page Caching cannot be used for actions that have before filters - for example, pages that require authentication. This is where Action Caching comes in. Action Caching works like Page Caching except the incoming web request hits the Rails stack so that before filters can be run on it before the cache is served. This allows authentication and other restrictions to be run while still serving the result of the output from a cached copy.
|
38
38
|
|
39
|
-
INFO: Action Caching has been removed from Rails 4. See the [actionpack-action_caching gem](https://github.com/rails/actionpack-action_caching). See [DHH's key-based cache expiration overview](http://
|
39
|
+
INFO: Action Caching has been removed from Rails 4. See the [actionpack-action_caching gem](https://github.com/rails/actionpack-action_caching). See [DHH's key-based cache expiration overview](http://signalvnoise.com/posts/3113-how-key-based-cache-expiration-works) for the newly-preferred method.
|
40
40
|
|
41
41
|
### Fragment Caching
|
42
42
|
|
@@ -105,7 +105,7 @@ This method generates a cache key that depends on all products and can be used i
|
|
105
105
|
<% end %>
|
106
106
|
```
|
107
107
|
|
108
|
-
If you want to cache a fragment under certain condition you can use `cache_if` or `cache_unless`
|
108
|
+
If you want to cache a fragment under certain condition you can use `cache_if` or `cache_unless`
|
109
109
|
|
110
110
|
```erb
|
111
111
|
<% cache_if (condition, cache_key_for_products) do %>
|
@@ -140,6 +140,26 @@ You can also combine the two schemes which is called "Russian Doll Caching":
|
|
140
140
|
|
141
141
|
It's called "Russian Doll Caching" because it nests multiple fragments. The advantage is that if a single product is updated, all the other inner fragments can be reused when regenerating the outer fragment.
|
142
142
|
|
143
|
+
### Low-Level Caching
|
144
|
+
|
145
|
+
Sometimes you need to cache a particular value or query result, instead of caching view fragments. Rails caching mechanism works great for storing __any__ kind of information.
|
146
|
+
|
147
|
+
The most efficient way to implement low-level caching is using the `Rails.cache.fetch` method. This method does both reading and writing to the cache. When passed only a single argument, the key is fetched and value from the cache is returned. If a block is passed, the result of the block will be cached to the given key and the result is returned.
|
148
|
+
|
149
|
+
Consider the following example. An application has a `Product` model with an instance method that looks up the product’s price on a competing website. The data returned by this method would be perfect for low-level caching:
|
150
|
+
|
151
|
+
```ruby
|
152
|
+
class Product < ActiveRecord::Base
|
153
|
+
def competing_price
|
154
|
+
Rails.cache.fetch("#{cache_key}/competing_price", expires_in: 12.hours) do
|
155
|
+
Competitor::API.find_price(id)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
```
|
160
|
+
|
161
|
+
NOTE: Notice that in this example we used `cache_key` method, so the resulting cache-key will be something like `products/233-20140225082222765838000/competing_price`. `cache_key` generates a string based on the model’s `id` and `updated_at` attributes. This is a common convention and has the benefit of invalidating the cache whenever the product is updated. In general, when you use low-level caching for instance level information, you need to generate a cache key.
|
162
|
+
|
143
163
|
### SQL Caching
|
144
164
|
|
145
165
|
Query caching is a Rails feature that caches the result set returned by each query so that if Rails encounters the same query again for that request, it will use the cached result set as opposed to running the query against the database again.
|
@@ -165,7 +185,7 @@ end
|
|
165
185
|
Cache Stores
|
166
186
|
------------
|
167
187
|
|
168
|
-
Rails provides different stores for the cached data created by
|
188
|
+
Rails provides different stores for the cached data created by **action** and **fragment** caches.
|
169
189
|
|
170
190
|
TIP: Page caches are always stored on disk.
|
171
191
|
|
@@ -333,12 +353,17 @@ Instead of an options hash, you can also simply pass in a model, Rails will use
|
|
333
353
|
class ProductsController < ApplicationController
|
334
354
|
def show
|
335
355
|
@product = Product.find(params[:id])
|
336
|
-
|
356
|
+
|
357
|
+
if stale?(@product)
|
358
|
+
respond_to do |wants|
|
359
|
+
# ... normal response processing
|
360
|
+
end
|
361
|
+
end
|
337
362
|
end
|
338
363
|
end
|
339
364
|
```
|
340
365
|
|
341
|
-
If you don't have any special response processing and are using the default rendering mechanism (i.e. you're not using respond_to or calling render yourself) then you've got an easy helper in fresh_when
|
366
|
+
If you don't have any special response processing and are using the default rendering mechanism (i.e. you're not using `respond_to` or calling render yourself) then you've got an easy helper in `fresh_when`:
|
342
367
|
|
343
368
|
```ruby
|
344
369
|
class ProductsController < ApplicationController
|