rails 4.1.4 → 4.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +12 -10
- data/guides/CHANGELOG.md +15 -25
- 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_gem.rb +2 -2
- data/guides/bug_report_templates/action_controller_master.rb +3 -2
- 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 +5 -2
- 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 +10 -11
- 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 +84 -10
- data/guides/source/action_mailer_basics.md +91 -28
- data/guides/source/action_view_overview.md +140 -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} +135 -226
- data/guides/source/active_record_postgresql.md +433 -0
- data/guides/source/active_record_querying.md +269 -259
- data/guides/source/active_record_validations.md +21 -12
- data/guides/source/active_support_core_extensions.md +113 -73
- data/guides/source/active_support_instrumentation.md +10 -7
- data/guides/source/api_documentation_guidelines.md +62 -16
- data/guides/source/asset_pipeline.md +264 -67
- 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 +448 -294
- data/guides/source/development_dependencies_install.md +47 -36
- data/guides/source/documents.yaml +19 -7
- data/guides/source/engines.md +210 -189
- data/guides/source/form_helpers.md +79 -56
- data/guides/source/generators.md +24 -11
- data/guides/source/getting_started.md +339 -201
- data/guides/source/i18n.md +111 -68
- data/guides/source/index.html.erb +1 -0
- data/guides/source/initialization.md +109 -62
- data/guides/source/layout.html.erb +1 -4
- data/guides/source/layouts_and_rendering.md +18 -17
- data/guides/source/maintenance_policy.md +26 -4
- 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 +12 -9
- data/guides/source/routing.md +100 -74
- data/guides/source/ruby_on_rails_guides_guidelines.md +11 -12
- data/guides/source/security.md +40 -34
- data/guides/source/testing.md +188 -117
- data/guides/source/upgrading_ruby_on_rails.md +284 -29
- data/guides/source/working_with_javascript_in_rails.md +18 -16
- data/guides/w3c_validator.rb +2 -0
- metadata +40 -94
- 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
|
@@ -18,9 +18,10 @@ After reading this guide, you will know:
|
|
|
18
18
|
Migration Overview
|
|
19
19
|
------------------
|
|
20
20
|
|
|
21
|
-
Migrations are a convenient way to
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
Migrations are a convenient way to
|
|
22
|
+
[alter your database schema over time](http://en.wikipedia.org/wiki/Schema_migration)
|
|
23
|
+
in a consistent and easy way. They use a Ruby DSL so that you don't have to
|
|
24
|
+
write SQL by hand, allowing your schema and changes to be database independent.
|
|
24
25
|
|
|
25
26
|
You can think of each migration as being a new 'version' of the database. A
|
|
26
27
|
schema starts off with nothing in it, and each migration modifies it to add or
|
|
@@ -38,7 +39,7 @@ class CreateProducts < ActiveRecord::Migration
|
|
|
38
39
|
t.string :name
|
|
39
40
|
t.text :description
|
|
40
41
|
|
|
41
|
-
t.timestamps
|
|
42
|
+
t.timestamps null: false
|
|
42
43
|
end
|
|
43
44
|
end
|
|
44
45
|
end
|
|
@@ -284,7 +285,7 @@ class CreateProducts < ActiveRecord::Migration
|
|
|
284
285
|
t.string :name
|
|
285
286
|
t.text :description
|
|
286
287
|
|
|
287
|
-
t.timestamps
|
|
288
|
+
t.timestamps null: false
|
|
288
289
|
end
|
|
289
290
|
end
|
|
290
291
|
end
|
|
@@ -292,16 +293,10 @@ end
|
|
|
292
293
|
|
|
293
294
|
You can append as many column name/type pairs as you want.
|
|
294
295
|
|
|
295
|
-
###
|
|
296
|
+
### Passing Modifiers
|
|
296
297
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
* `limit` Sets the maximum size of the `string/text/binary/integer` fields.
|
|
301
|
-
* `precision` Defines the precision for the `decimal` fields, representing the total number of digits in the number.
|
|
302
|
-
* `scale` Defines the scale for the `decimal` fields, representing the number of digits after the decimal point.
|
|
303
|
-
* `polymorphic` Adds a `type` column for `belongs_to` associations.
|
|
304
|
-
* `null` Allows or disallows `NULL` values in the column.
|
|
298
|
+
Some commonly used [type modifiers](#column-modifiers) can be passed directly on
|
|
299
|
+
the command line. They are enclosed by curly braces and follow the field type:
|
|
305
300
|
|
|
306
301
|
For instance, running:
|
|
307
302
|
|
|
@@ -320,6 +315,8 @@ class AddDetailsToProducts < ActiveRecord::Migration
|
|
|
320
315
|
end
|
|
321
316
|
```
|
|
322
317
|
|
|
318
|
+
TIP: Have a look at the generators help output for further details.
|
|
319
|
+
|
|
323
320
|
Writing a Migration
|
|
324
321
|
-------------------
|
|
325
322
|
|
|
@@ -414,6 +411,87 @@ end
|
|
|
414
411
|
removes the `description` and `name` columns, creates a `part_number` string
|
|
415
412
|
column and adds an index on it. Finally it renames the `upccode` column.
|
|
416
413
|
|
|
414
|
+
### Changing Columns
|
|
415
|
+
|
|
416
|
+
Like the `remove_column` and `add_column` Rails provides the `change_column`
|
|
417
|
+
migration method.
|
|
418
|
+
|
|
419
|
+
```ruby
|
|
420
|
+
change_column :products, :part_number, :text
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
This changes the column `part_number` on products table to be a `:text` field.
|
|
424
|
+
|
|
425
|
+
Besides `change_column`, the `change_column_null` and `change_column_default`
|
|
426
|
+
methods are used specifically to change the null and default values of a
|
|
427
|
+
column.
|
|
428
|
+
|
|
429
|
+
```ruby
|
|
430
|
+
change_column_null :products, :name, false
|
|
431
|
+
change_column_default :products, :approved, false
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
This sets `:name` field on products to a `NOT NULL` column and the default
|
|
435
|
+
value of the `:approved` field to false.
|
|
436
|
+
|
|
437
|
+
TIP: Unlike `change_column` (and `change_column_default`), `change_column_null`
|
|
438
|
+
is reversible.
|
|
439
|
+
|
|
440
|
+
### Column Modifiers
|
|
441
|
+
|
|
442
|
+
Column modifiers can be applied when creating or changing a column:
|
|
443
|
+
|
|
444
|
+
* `limit` Sets the maximum size of the `string/text/binary/integer` fields.
|
|
445
|
+
* `precision` Defines the precision for the `decimal` fields, representing the
|
|
446
|
+
total number of digits in the number.
|
|
447
|
+
* `scale` Defines the scale for the `decimal` fields, representing the
|
|
448
|
+
number of digits after the decimal point.
|
|
449
|
+
* `polymorphic` Adds a `type` column for `belongs_to` associations.
|
|
450
|
+
* `null` Allows or disallows `NULL` values in the column.
|
|
451
|
+
* `default` Allows to set a default value on the column. Note that if you
|
|
452
|
+
are using a dynamic value (such as a date), the default will only be calculated
|
|
453
|
+
the first time (i.e. on the date the migration is applied).
|
|
454
|
+
* `index` Adds an index for the column.
|
|
455
|
+
* `required` Adds `required: true` for `belongs_to` associations and
|
|
456
|
+
`null: false` to the column in the migration.
|
|
457
|
+
|
|
458
|
+
Some adapters may support additional options; see the adapter specific API docs
|
|
459
|
+
for further information.
|
|
460
|
+
|
|
461
|
+
### Foreign Keys
|
|
462
|
+
|
|
463
|
+
While it's not required you might want to add foreign key constraints to
|
|
464
|
+
[guarantee referential integrity](#active-record-and-referential-integrity).
|
|
465
|
+
|
|
466
|
+
```ruby
|
|
467
|
+
add_foreign_key :articles, :authors
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
This adds a new foreign key to the `author_id` column of the `articles`
|
|
471
|
+
table. The key references the `id` column of the `authors` table. If the
|
|
472
|
+
column names can not be derived from the table names, you can use the
|
|
473
|
+
`:column` and `:primary_key` options.
|
|
474
|
+
|
|
475
|
+
Rails will generate a name for every foreign key starting with
|
|
476
|
+
`fk_rails_` followed by 10 random characters.
|
|
477
|
+
There is a `:name` option to specify a different name if needed.
|
|
478
|
+
|
|
479
|
+
NOTE: Active Record only supports single column foreign keys. `execute` and
|
|
480
|
+
`structure.sql` are required to use composite foreign keys.
|
|
481
|
+
|
|
482
|
+
Removing a foreign key is easy as well:
|
|
483
|
+
|
|
484
|
+
```ruby
|
|
485
|
+
# let Active Record figure out the column name
|
|
486
|
+
remove_foreign_key :accounts, :branches
|
|
487
|
+
|
|
488
|
+
# remove foreign key for a specific column
|
|
489
|
+
remove_foreign_key :accounts, column: :owner_id
|
|
490
|
+
|
|
491
|
+
# remove foreign key by name
|
|
492
|
+
remove_foreign_key :accounts, name: :special_fk_name
|
|
493
|
+
```
|
|
494
|
+
|
|
417
495
|
### When Helpers aren't Enough
|
|
418
496
|
|
|
419
497
|
If the helpers provided by Active Record aren't enough you can use the `execute`
|
|
@@ -444,6 +522,7 @@ definitions:
|
|
|
444
522
|
* `add_index`
|
|
445
523
|
* `add_reference`
|
|
446
524
|
* `add_timestamps`
|
|
525
|
+
* `add_foreign_key`
|
|
447
526
|
* `create_table`
|
|
448
527
|
* `create_join_table`
|
|
449
528
|
* `drop_table` (must supply a block)
|
|
@@ -469,24 +548,23 @@ migration what else to do when reverting it. For example:
|
|
|
469
548
|
```ruby
|
|
470
549
|
class ExampleMigration < ActiveRecord::Migration
|
|
471
550
|
def change
|
|
472
|
-
create_table :
|
|
473
|
-
t.
|
|
551
|
+
create_table :distributors do |t|
|
|
552
|
+
t.string :zipcode
|
|
474
553
|
end
|
|
475
554
|
|
|
476
555
|
reversible do |dir|
|
|
477
556
|
dir.up do
|
|
478
|
-
#add a
|
|
557
|
+
# add a CHECK constraint
|
|
479
558
|
execute <<-SQL
|
|
480
|
-
ALTER TABLE
|
|
481
|
-
ADD CONSTRAINT
|
|
482
|
-
|
|
483
|
-
REFERENCES categories(id)
|
|
559
|
+
ALTER TABLE distributors
|
|
560
|
+
ADD CONSTRAINT zipchk
|
|
561
|
+
CHECK (char_length(zipcode) = 5) NO INHERIT;
|
|
484
562
|
SQL
|
|
485
563
|
end
|
|
486
564
|
dir.down do
|
|
487
565
|
execute <<-SQL
|
|
488
|
-
ALTER TABLE
|
|
489
|
-
DROP
|
|
566
|
+
ALTER TABLE distributors
|
|
567
|
+
DROP CONSTRAINT zipchk
|
|
490
568
|
SQL
|
|
491
569
|
end
|
|
492
570
|
end
|
|
@@ -500,7 +578,7 @@ end
|
|
|
500
578
|
Using `reversible` will ensure that the instructions are executed in the
|
|
501
579
|
right order too. If the previous example migration is reverted,
|
|
502
580
|
the `down` block will be run after the `home_page_url` column is removed and
|
|
503
|
-
right before the table `
|
|
581
|
+
right before the table `distributors` is dropped.
|
|
504
582
|
|
|
505
583
|
Sometimes your migration will do something which is just plain irreversible; for
|
|
506
584
|
example, it might destroy some data. In such cases, you can raise
|
|
@@ -523,16 +601,15 @@ made in the `up` method. The example in the `reversible` section is equivalent t
|
|
|
523
601
|
```ruby
|
|
524
602
|
class ExampleMigration < ActiveRecord::Migration
|
|
525
603
|
def up
|
|
526
|
-
create_table :
|
|
527
|
-
t.
|
|
604
|
+
create_table :distributors do |t|
|
|
605
|
+
t.string :zipcode
|
|
528
606
|
end
|
|
529
607
|
|
|
530
|
-
# add a
|
|
608
|
+
# add a CHECK constraint
|
|
531
609
|
execute <<-SQL
|
|
532
|
-
ALTER TABLE
|
|
533
|
-
ADD CONSTRAINT
|
|
534
|
-
|
|
535
|
-
REFERENCES categories(id)
|
|
610
|
+
ALTER TABLE distributors
|
|
611
|
+
ADD CONSTRAINT zipchk
|
|
612
|
+
CHECK (char_length(zipcode) = 5);
|
|
536
613
|
SQL
|
|
537
614
|
|
|
538
615
|
add_column :users, :home_page_url, :string
|
|
@@ -544,11 +621,11 @@ class ExampleMigration < ActiveRecord::Migration
|
|
|
544
621
|
remove_column :users, :home_page_url
|
|
545
622
|
|
|
546
623
|
execute <<-SQL
|
|
547
|
-
ALTER TABLE
|
|
548
|
-
DROP
|
|
624
|
+
ALTER TABLE distributors
|
|
625
|
+
DROP CONSTRAINT zipchk
|
|
549
626
|
SQL
|
|
550
627
|
|
|
551
|
-
drop_table :
|
|
628
|
+
drop_table :distributors
|
|
552
629
|
end
|
|
553
630
|
end
|
|
554
631
|
```
|
|
@@ -579,43 +656,27 @@ end
|
|
|
579
656
|
The `revert` method also accepts a block of instructions to reverse.
|
|
580
657
|
This could be useful to revert selected parts of previous migrations.
|
|
581
658
|
For example, let's imagine that `ExampleMigration` is committed and it
|
|
582
|
-
is later decided it would be best to
|
|
583
|
-
|
|
659
|
+
is later decided it would be best to use Active Record validations,
|
|
660
|
+
in place of the `CHECK` constraint, to verify the zipcode.
|
|
584
661
|
|
|
585
662
|
```ruby
|
|
586
|
-
class
|
|
663
|
+
class DontUseConstraintForZipcodeValidationMigration < ActiveRecord::Migration
|
|
587
664
|
def change
|
|
588
|
-
add_column :categories, :product_list
|
|
589
|
-
|
|
590
|
-
reversible do |dir|
|
|
591
|
-
dir.up do
|
|
592
|
-
# transfer data from Products to Category#product_list
|
|
593
|
-
end
|
|
594
|
-
dir.down do
|
|
595
|
-
# create Products from Category#product_list
|
|
596
|
-
end
|
|
597
|
-
end
|
|
598
|
-
|
|
599
665
|
revert do
|
|
600
666
|
# copy-pasted code from ExampleMigration
|
|
601
|
-
create_table :products do |t|
|
|
602
|
-
t.references :category
|
|
603
|
-
end
|
|
604
|
-
|
|
605
667
|
reversible do |dir|
|
|
606
668
|
dir.up do
|
|
607
|
-
#add a
|
|
669
|
+
# add a CHECK constraint
|
|
608
670
|
execute <<-SQL
|
|
609
|
-
ALTER TABLE
|
|
610
|
-
ADD CONSTRAINT
|
|
611
|
-
|
|
612
|
-
REFERENCES categories(id)
|
|
671
|
+
ALTER TABLE distributors
|
|
672
|
+
ADD CONSTRAINT zipchk
|
|
673
|
+
CHECK (char_length(zipcode) = 5);
|
|
613
674
|
SQL
|
|
614
675
|
end
|
|
615
676
|
dir.down do
|
|
616
677
|
execute <<-SQL
|
|
617
|
-
ALTER TABLE
|
|
618
|
-
DROP
|
|
678
|
+
ALTER TABLE distributors
|
|
679
|
+
DROP CONSTRAINT zipchk
|
|
619
680
|
SQL
|
|
620
681
|
end
|
|
621
682
|
end
|
|
@@ -765,7 +826,7 @@ class CreateProducts < ActiveRecord::Migration
|
|
|
765
826
|
create_table :products do |t|
|
|
766
827
|
t.string :name
|
|
767
828
|
t.text :description
|
|
768
|
-
t.timestamps
|
|
829
|
+
t.timestamps null: false
|
|
769
830
|
end
|
|
770
831
|
end
|
|
771
832
|
|
|
@@ -819,159 +880,6 @@ The `revert` method can be helpful when writing a new migration to undo
|
|
|
819
880
|
previous migrations in whole or in part
|
|
820
881
|
(see [Reverting Previous Migrations](#reverting-previous-migrations) above).
|
|
821
882
|
|
|
822
|
-
Using Models in Your Migrations
|
|
823
|
-
-------------------------------
|
|
824
|
-
|
|
825
|
-
When creating or updating data in a migration it is often tempting to use one
|
|
826
|
-
of your models. After all, they exist to provide easy access to the underlying
|
|
827
|
-
data. This can be done, but some caution should be observed.
|
|
828
|
-
|
|
829
|
-
For example, problems occur when the model uses database columns which are (1)
|
|
830
|
-
not currently in the database and (2) will be created by this or a subsequent
|
|
831
|
-
migration.
|
|
832
|
-
|
|
833
|
-
Consider this example, where Alice and Bob are working on the same code base
|
|
834
|
-
which contains a `Product` model:
|
|
835
|
-
|
|
836
|
-
Bob goes on vacation.
|
|
837
|
-
|
|
838
|
-
Alice creates a migration for the `products` table which adds a new column and
|
|
839
|
-
initializes it:
|
|
840
|
-
|
|
841
|
-
```ruby
|
|
842
|
-
# db/migrate/20100513121110_add_flag_to_product.rb
|
|
843
|
-
|
|
844
|
-
class AddFlagToProduct < ActiveRecord::Migration
|
|
845
|
-
def change
|
|
846
|
-
add_column :products, :flag, :boolean
|
|
847
|
-
reversible do |dir|
|
|
848
|
-
dir.up { Product.update_all flag: false }
|
|
849
|
-
end
|
|
850
|
-
end
|
|
851
|
-
end
|
|
852
|
-
```
|
|
853
|
-
|
|
854
|
-
She also adds a validation to the `Product` model for the new column:
|
|
855
|
-
|
|
856
|
-
```ruby
|
|
857
|
-
# app/models/product.rb
|
|
858
|
-
|
|
859
|
-
class Product < ActiveRecord::Base
|
|
860
|
-
validates :flag, inclusion: { in: [true, false] }
|
|
861
|
-
end
|
|
862
|
-
```
|
|
863
|
-
|
|
864
|
-
Alice adds a second migration which adds another column to the `products`
|
|
865
|
-
table and initializes it:
|
|
866
|
-
|
|
867
|
-
```ruby
|
|
868
|
-
# db/migrate/20100515121110_add_fuzz_to_product.rb
|
|
869
|
-
|
|
870
|
-
class AddFuzzToProduct < ActiveRecord::Migration
|
|
871
|
-
def change
|
|
872
|
-
add_column :products, :fuzz, :string
|
|
873
|
-
reversible do |dir|
|
|
874
|
-
dir.up { Product.update_all fuzz: 'fuzzy' }
|
|
875
|
-
end
|
|
876
|
-
end
|
|
877
|
-
end
|
|
878
|
-
```
|
|
879
|
-
|
|
880
|
-
She also adds a validation to the `Product` model for the new column:
|
|
881
|
-
|
|
882
|
-
```ruby
|
|
883
|
-
# app/models/product.rb
|
|
884
|
-
|
|
885
|
-
class Product < ActiveRecord::Base
|
|
886
|
-
validates :flag, inclusion: { in: [true, false] }
|
|
887
|
-
validates :fuzz, presence: true
|
|
888
|
-
end
|
|
889
|
-
```
|
|
890
|
-
|
|
891
|
-
Both migrations work for Alice.
|
|
892
|
-
|
|
893
|
-
Bob comes back from vacation and:
|
|
894
|
-
|
|
895
|
-
* Updates the source - which contains both migrations and the latest version
|
|
896
|
-
of the Product model.
|
|
897
|
-
* Runs outstanding migrations with `rake db:migrate`, which
|
|
898
|
-
includes the one that updates the `Product` model.
|
|
899
|
-
|
|
900
|
-
The migration crashes because when the model attempts to save, it tries to
|
|
901
|
-
validate the second added column, which is not in the database when the _first_
|
|
902
|
-
migration runs:
|
|
903
|
-
|
|
904
|
-
```
|
|
905
|
-
rake aborted!
|
|
906
|
-
An error has occurred, this and all later migrations canceled:
|
|
907
|
-
|
|
908
|
-
undefined method `fuzz' for #<Product:0x000001049b14a0>
|
|
909
|
-
```
|
|
910
|
-
|
|
911
|
-
A fix for this is to create a local model within the migration. This keeps
|
|
912
|
-
Rails from running the validations, so that the migrations run to completion.
|
|
913
|
-
|
|
914
|
-
When using a local model, it's a good idea to call
|
|
915
|
-
`Product.reset_column_information` to refresh the Active Record cache for the
|
|
916
|
-
`Product` model prior to updating data in the database.
|
|
917
|
-
|
|
918
|
-
If Alice had done this instead, there would have been no problem:
|
|
919
|
-
|
|
920
|
-
```ruby
|
|
921
|
-
# db/migrate/20100513121110_add_flag_to_product.rb
|
|
922
|
-
|
|
923
|
-
class AddFlagToProduct < ActiveRecord::Migration
|
|
924
|
-
class Product < ActiveRecord::Base
|
|
925
|
-
end
|
|
926
|
-
|
|
927
|
-
def change
|
|
928
|
-
add_column :products, :flag, :boolean
|
|
929
|
-
Product.reset_column_information
|
|
930
|
-
reversible do |dir|
|
|
931
|
-
dir.up { Product.update_all flag: false }
|
|
932
|
-
end
|
|
933
|
-
end
|
|
934
|
-
end
|
|
935
|
-
```
|
|
936
|
-
|
|
937
|
-
```ruby
|
|
938
|
-
# db/migrate/20100515121110_add_fuzz_to_product.rb
|
|
939
|
-
|
|
940
|
-
class AddFuzzToProduct < ActiveRecord::Migration
|
|
941
|
-
class Product < ActiveRecord::Base
|
|
942
|
-
end
|
|
943
|
-
|
|
944
|
-
def change
|
|
945
|
-
add_column :products, :fuzz, :string
|
|
946
|
-
Product.reset_column_information
|
|
947
|
-
reversible do |dir|
|
|
948
|
-
dir.up { Product.update_all fuzz: 'fuzzy' }
|
|
949
|
-
end
|
|
950
|
-
end
|
|
951
|
-
end
|
|
952
|
-
```
|
|
953
|
-
|
|
954
|
-
There are other ways in which the above example could have gone badly.
|
|
955
|
-
|
|
956
|
-
For example, imagine that Alice creates a migration that selectively
|
|
957
|
-
updates the `description` field on certain products. She runs the
|
|
958
|
-
migration, commits the code, and then begins working on the next feature,
|
|
959
|
-
which is to add a new column `fuzz` to the products table.
|
|
960
|
-
|
|
961
|
-
She creates two migrations for this new feature, one which adds the new
|
|
962
|
-
column, and a second which selectively updates the `fuzz` column based on
|
|
963
|
-
other product attributes.
|
|
964
|
-
|
|
965
|
-
These migrations run just fine, but when Bob comes back from his vacation
|
|
966
|
-
and calls `rake db:migrate` to run all the outstanding migrations, he gets a
|
|
967
|
-
subtle bug: The descriptions have defaults, and the `fuzz` column is present,
|
|
968
|
-
but `fuzz` is `nil` on all products.
|
|
969
|
-
|
|
970
|
-
The solution is again to use `Product.reset_column_information` before
|
|
971
|
-
referencing the Product model in a migration, ensuring the Active Record's
|
|
972
|
-
knowledge of the table structure is current before manipulating data in those
|
|
973
|
-
records.
|
|
974
|
-
|
|
975
883
|
Schema Dumping and You
|
|
976
884
|
----------------------
|
|
977
885
|
|
|
@@ -1033,10 +941,10 @@ that Active Record supports. This could be very useful if you were to
|
|
|
1033
941
|
distribute an application that is able to run against multiple databases.
|
|
1034
942
|
|
|
1035
943
|
There is however a trade-off: `db/schema.rb` cannot express database specific
|
|
1036
|
-
items such as
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
944
|
+
items such as triggers, or stored procedures. While in a migration you can
|
|
945
|
+
execute custom SQL statements, the schema dumper cannot reconstitute those
|
|
946
|
+
statements from the database. If you are using features like this, then you
|
|
947
|
+
should set the schema format to `:sql`.
|
|
1040
948
|
|
|
1041
949
|
Instead of using Active Record's schema dumper, the database's structure will
|
|
1042
950
|
be dumped using a tool specific to the database (via the `db:structure:dump`
|
|
@@ -1054,11 +962,16 @@ schema into a RDBMS other than the one used to create it.
|
|
|
1054
962
|
Because schema dumps are the authoritative source for your database schema, it
|
|
1055
963
|
is strongly recommended that you check them into source control.
|
|
1056
964
|
|
|
965
|
+
`db/schema.rb` contains the current version number of the database. This
|
|
966
|
+
ensures conflicts are going to happen in the case of a merge where both
|
|
967
|
+
branches touched the schema. When that happens, solve conflicts manually,
|
|
968
|
+
keeping the highest version number of the two.
|
|
969
|
+
|
|
1057
970
|
Active Record and Referential Integrity
|
|
1058
971
|
---------------------------------------
|
|
1059
972
|
|
|
1060
973
|
The Active Record way claims that intelligence belongs in your models, not in
|
|
1061
|
-
the database. As such, features such as triggers or
|
|
974
|
+
the database. As such, features such as triggers or constraints,
|
|
1062
975
|
which push some of that intelligence back into the database, are not heavily
|
|
1063
976
|
used.
|
|
1064
977
|
|
|
@@ -1067,14 +980,10 @@ which models can enforce data integrity. The `:dependent` option on
|
|
|
1067
980
|
associations allows models to automatically destroy child objects when the
|
|
1068
981
|
parent is destroyed. Like anything which operates at the application level,
|
|
1069
982
|
these cannot guarantee referential integrity and so some people augment them
|
|
1070
|
-
with foreign key constraints in the database.
|
|
1071
|
-
|
|
1072
|
-
Although Active Record does not provide
|
|
1073
|
-
such features, the `execute` method can be used to execute arbitrary SQL.
|
|
1074
|
-
can also use a gem like
|
|
1075
|
-
[foreigner](https://github.com/matthuhiggins/foreigner) which adds foreign key
|
|
1076
|
-
support to Active Record (including support for dumping foreign keys in
|
|
1077
|
-
`db/schema.rb`).
|
|
983
|
+
with [foreign key constraints](#foreign-keys) in the database.
|
|
984
|
+
|
|
985
|
+
Although Active Record does not provide all the tools for working directly with
|
|
986
|
+
such features, the `execute` method can be used to execute arbitrary SQL.
|
|
1078
987
|
|
|
1079
988
|
Migrations and Seed Data
|
|
1080
989
|
------------------------
|