rails 4.1.14.2 → 4.2.11.1
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 +5 -5
- data/README.md +12 -10
- data/guides/CHANGELOG.md +34 -37
- data/guides/Rakefile +21 -6
- data/guides/assets/images/getting_started/article_with_comments.png +0 -0
- data/guides/assets/javascripts/guides.js +6 -0
- data/guides/assets/stylesheets/main.css +4 -1
- data/guides/bug_report_templates/action_controller_gem.rb +1 -1
- data/guides/bug_report_templates/action_controller_master.rb +1 -0
- data/guides/bug_report_templates/active_record_gem.rb +1 -1
- data/guides/bug_report_templates/generic_gem.rb +1 -1
- data/guides/rails_guides/helpers.rb +1 -1
- data/guides/rails_guides/levenshtein.rb +27 -21
- data/guides/rails_guides/markdown/renderer.rb +1 -1
- data/guides/rails_guides/markdown.rb +11 -7
- data/guides/rails_guides.rb +2 -2
- data/guides/source/2_2_release_notes.md +1 -1
- data/guides/source/2_3_release_notes.md +4 -4
- data/guides/source/3_0_release_notes.md +8 -8
- data/guides/source/3_1_release_notes.md +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 +5 -6
- data/guides/source/4_2_release_notes.md +877 -0
- data/guides/source/_license.html.erb +1 -1
- data/guides/source/_welcome.html.erb +6 -8
- data/guides/source/action_controller_overview.md +25 -8
- data/guides/source/action_mailer_basics.md +97 -29
- data/guides/source/action_view_overview.md +142 -183
- data/guides/source/active_job_basics.md +339 -0
- data/guides/source/active_model_basics.md +371 -17
- data/guides/source/active_record_basics.md +25 -24
- data/guides/source/active_record_callbacks.md +12 -9
- data/guides/source/{migrations.md → active_record_migrations.md} +95 -220
- data/guides/source/active_record_postgresql.md +433 -0
- data/guides/source/active_record_querying.md +264 -268
- data/guides/source/active_record_validations.md +23 -13
- data/guides/source/active_support_core_extensions.md +114 -75
- data/guides/source/active_support_instrumentation.md +10 -18
- data/guides/source/api_documentation_guidelines.md +63 -17
- data/guides/source/asset_pipeline.md +258 -119
- data/guides/source/association_basics.md +96 -80
- data/guides/source/autoloading_and_reloading_constants.md +1311 -0
- data/guides/source/caching_with_rails.md +32 -7
- data/guides/source/command_line.md +52 -30
- data/guides/source/configuring.md +161 -33
- data/guides/source/contributing_to_ruby_on_rails.md +198 -114
- data/guides/source/credits.html.erb +2 -2
- data/guides/source/debugging_rails_applications.md +440 -286
- data/guides/source/development_dependencies_install.md +47 -36
- data/guides/source/documents.yaml +19 -7
- data/guides/source/engines.md +189 -189
- data/guides/source/form_helpers.md +79 -56
- data/guides/source/generators.md +24 -11
- data/guides/source/getting_started.md +359 -219
- data/guides/source/i18n.md +110 -66
- data/guides/source/index.html.erb +1 -0
- data/guides/source/initialization.md +109 -62
- data/guides/source/layout.html.erb +5 -11
- data/guides/source/layouts_and_rendering.md +26 -26
- data/guides/source/maintenance_policy.md +6 -3
- data/guides/source/nested_model_forms.md +7 -4
- data/guides/source/plugins.md +27 -27
- data/guides/source/rails_application_templates.md +21 -3
- data/guides/source/rails_on_rack.md +8 -5
- data/guides/source/routing.md +113 -73
- data/guides/source/ruby_on_rails_guides_guidelines.md +11 -12
- data/guides/source/security.md +39 -33
- data/guides/source/testing.md +199 -119
- data/guides/source/upgrading_ruby_on_rails.md +287 -29
- data/guides/source/working_with_javascript_in_rails.md +19 -17
- data/guides/w3c_validator.rb +2 -0
- metadata +40 -95
- data/guides/code/getting_started/Gemfile +0 -40
- data/guides/code/getting_started/Gemfile.lock +0 -125
- data/guides/code/getting_started/README.rdoc +0 -28
- data/guides/code/getting_started/Rakefile +0 -6
- data/guides/code/getting_started/app/assets/javascripts/application.js +0 -15
- data/guides/code/getting_started/app/assets/javascripts/comments.js.coffee +0 -3
- data/guides/code/getting_started/app/assets/javascripts/posts.js.coffee +0 -3
- data/guides/code/getting_started/app/assets/javascripts/welcome.js.coffee +0 -3
- data/guides/code/getting_started/app/assets/stylesheets/application.css +0 -13
- data/guides/code/getting_started/app/assets/stylesheets/comments.css.scss +0 -3
- data/guides/code/getting_started/app/assets/stylesheets/posts.css.scss +0 -3
- data/guides/code/getting_started/app/assets/stylesheets/welcome.css.scss +0 -3
- data/guides/code/getting_started/app/controllers/application_controller.rb +0 -5
- data/guides/code/getting_started/app/controllers/comments_controller.rb +0 -23
- data/guides/code/getting_started/app/controllers/posts_controller.rb +0 -53
- data/guides/code/getting_started/app/controllers/welcome_controller.rb +0 -4
- data/guides/code/getting_started/app/helpers/application_helper.rb +0 -2
- data/guides/code/getting_started/app/helpers/comments_helper.rb +0 -2
- data/guides/code/getting_started/app/helpers/posts_helper.rb +0 -2
- data/guides/code/getting_started/app/helpers/welcome_helper.rb +0 -2
- data/guides/code/getting_started/app/models/comment.rb +0 -3
- data/guides/code/getting_started/app/models/post.rb +0 -7
- data/guides/code/getting_started/app/views/comments/_comment.html.erb +0 -15
- data/guides/code/getting_started/app/views/comments/_form.html.erb +0 -13
- data/guides/code/getting_started/app/views/layouts/application.html.erb +0 -14
- data/guides/code/getting_started/app/views/posts/_form.html.erb +0 -27
- data/guides/code/getting_started/app/views/posts/edit.html.erb +0 -5
- data/guides/code/getting_started/app/views/posts/index.html.erb +0 -21
- data/guides/code/getting_started/app/views/posts/new.html.erb +0 -5
- data/guides/code/getting_started/app/views/posts/show.html.erb +0 -18
- data/guides/code/getting_started/app/views/welcome/index.html.erb +0 -4
- data/guides/code/getting_started/bin/bundle +0 -4
- data/guides/code/getting_started/bin/rails +0 -4
- data/guides/code/getting_started/bin/rake +0 -4
- data/guides/code/getting_started/config/application.rb +0 -18
- data/guides/code/getting_started/config/boot.rb +0 -4
- data/guides/code/getting_started/config/database.yml +0 -25
- data/guides/code/getting_started/config/environment.rb +0 -5
- data/guides/code/getting_started/config/environments/development.rb +0 -30
- data/guides/code/getting_started/config/environments/production.rb +0 -80
- data/guides/code/getting_started/config/environments/test.rb +0 -36
- data/guides/code/getting_started/config/initializers/backtrace_silencers.rb +0 -7
- data/guides/code/getting_started/config/initializers/filter_parameter_logging.rb +0 -4
- data/guides/code/getting_started/config/initializers/inflections.rb +0 -16
- data/guides/code/getting_started/config/initializers/locale.rb +0 -9
- data/guides/code/getting_started/config/initializers/mime_types.rb +0 -5
- data/guides/code/getting_started/config/initializers/secret_token.rb +0 -12
- data/guides/code/getting_started/config/initializers/session_store.rb +0 -3
- data/guides/code/getting_started/config/initializers/wrap_parameters.rb +0 -14
- data/guides/code/getting_started/config/locales/en.yml +0 -23
- data/guides/code/getting_started/config/routes.rb +0 -7
- data/guides/code/getting_started/config.ru +0 -4
- data/guides/code/getting_started/db/migrate/20130122042648_create_posts.rb +0 -10
- data/guides/code/getting_started/db/migrate/20130122045842_create_comments.rb +0 -11
- data/guides/code/getting_started/db/schema.rb +0 -33
- data/guides/code/getting_started/db/seeds.rb +0 -7
- data/guides/code/getting_started/public/404.html +0 -60
- data/guides/code/getting_started/public/422.html +0 -60
- data/guides/code/getting_started/public/500.html +0 -59
- data/guides/code/getting_started/public/favicon.ico +0 -0
- data/guides/code/getting_started/public/robots.txt +0 -5
- data/guides/code/getting_started/test/controllers/comments_controller_test.rb +0 -7
- data/guides/code/getting_started/test/controllers/posts_controller_test.rb +0 -7
- data/guides/code/getting_started/test/controllers/welcome_controller_test.rb +0 -9
- data/guides/code/getting_started/test/fixtures/comments.yml +0 -11
- data/guides/code/getting_started/test/fixtures/posts.yml +0 -9
- data/guides/code/getting_started/test/helpers/comments_helper_test.rb +0 -4
- data/guides/code/getting_started/test/helpers/posts_helper_test.rb +0 -4
- data/guides/code/getting_started/test/helpers/welcome_helper_test.rb +0 -4
- data/guides/code/getting_started/test/models/comment_test.rb +0 -7
- data/guides/code/getting_started/test/models/post_test.rb +0 -7
- data/guides/code/getting_started/test/test_helper.rb +0 -12
|
@@ -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
|
|
@@ -433,21 +434,64 @@ change_column_default :products, :approved, false
|
|
|
433
434
|
This sets `:name` field on products to a `NOT NULL` column and the default
|
|
434
435
|
value of the `:approved` field to false.
|
|
435
436
|
|
|
437
|
+
TIP: Unlike `change_column` (and `change_column_default`), `change_column_null`
|
|
438
|
+
is reversible.
|
|
439
|
+
|
|
436
440
|
### Column Modifiers
|
|
437
441
|
|
|
438
442
|
Column modifiers can be applied when creating or changing a column:
|
|
439
443
|
|
|
440
444
|
* `limit` Sets the maximum size of the `string/text/binary/integer` fields.
|
|
441
|
-
* `precision` Defines the precision for the `decimal` fields, representing the
|
|
442
|
-
|
|
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.
|
|
443
449
|
* `polymorphic` Adds a `type` column for `belongs_to` associations.
|
|
444
450
|
* `null` Allows or disallows `NULL` values in the column.
|
|
445
|
-
* `default` Allows to set a default value on 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).
|
|
446
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.
|
|
447
457
|
|
|
448
458
|
Some adapters may support additional options; see the adapter specific API docs
|
|
449
459
|
for further information.
|
|
450
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
|
+
|
|
451
495
|
### When Helpers aren't Enough
|
|
452
496
|
|
|
453
497
|
If the helpers provided by Active Record aren't enough you can use the `execute`
|
|
@@ -478,6 +522,7 @@ definitions:
|
|
|
478
522
|
* `add_index`
|
|
479
523
|
* `add_reference`
|
|
480
524
|
* `add_timestamps`
|
|
525
|
+
* `add_foreign_key`
|
|
481
526
|
* `create_table`
|
|
482
527
|
* `create_join_table`
|
|
483
528
|
* `drop_table` (must supply a block)
|
|
@@ -503,24 +548,23 @@ migration what else to do when reverting it. For example:
|
|
|
503
548
|
```ruby
|
|
504
549
|
class ExampleMigration < ActiveRecord::Migration
|
|
505
550
|
def change
|
|
506
|
-
create_table :
|
|
507
|
-
t.
|
|
551
|
+
create_table :distributors do |t|
|
|
552
|
+
t.string :zipcode
|
|
508
553
|
end
|
|
509
554
|
|
|
510
555
|
reversible do |dir|
|
|
511
556
|
dir.up do
|
|
512
|
-
#add a
|
|
557
|
+
# add a CHECK constraint
|
|
513
558
|
execute <<-SQL
|
|
514
|
-
ALTER TABLE
|
|
515
|
-
ADD CONSTRAINT
|
|
516
|
-
|
|
517
|
-
REFERENCES categories(id)
|
|
559
|
+
ALTER TABLE distributors
|
|
560
|
+
ADD CONSTRAINT zipchk
|
|
561
|
+
CHECK (char_length(zipcode) = 5) NO INHERIT;
|
|
518
562
|
SQL
|
|
519
563
|
end
|
|
520
564
|
dir.down do
|
|
521
565
|
execute <<-SQL
|
|
522
|
-
ALTER TABLE
|
|
523
|
-
DROP
|
|
566
|
+
ALTER TABLE distributors
|
|
567
|
+
DROP CONSTRAINT zipchk
|
|
524
568
|
SQL
|
|
525
569
|
end
|
|
526
570
|
end
|
|
@@ -534,7 +578,7 @@ end
|
|
|
534
578
|
Using `reversible` will ensure that the instructions are executed in the
|
|
535
579
|
right order too. If the previous example migration is reverted,
|
|
536
580
|
the `down` block will be run after the `home_page_url` column is removed and
|
|
537
|
-
right before the table `
|
|
581
|
+
right before the table `distributors` is dropped.
|
|
538
582
|
|
|
539
583
|
Sometimes your migration will do something which is just plain irreversible; for
|
|
540
584
|
example, it might destroy some data. In such cases, you can raise
|
|
@@ -557,16 +601,15 @@ made in the `up` method. The example in the `reversible` section is equivalent t
|
|
|
557
601
|
```ruby
|
|
558
602
|
class ExampleMigration < ActiveRecord::Migration
|
|
559
603
|
def up
|
|
560
|
-
create_table :
|
|
561
|
-
t.
|
|
604
|
+
create_table :distributors do |t|
|
|
605
|
+
t.string :zipcode
|
|
562
606
|
end
|
|
563
607
|
|
|
564
|
-
# add a
|
|
608
|
+
# add a CHECK constraint
|
|
565
609
|
execute <<-SQL
|
|
566
|
-
ALTER TABLE
|
|
567
|
-
ADD CONSTRAINT
|
|
568
|
-
|
|
569
|
-
REFERENCES categories(id)
|
|
610
|
+
ALTER TABLE distributors
|
|
611
|
+
ADD CONSTRAINT zipchk
|
|
612
|
+
CHECK (char_length(zipcode) = 5);
|
|
570
613
|
SQL
|
|
571
614
|
|
|
572
615
|
add_column :users, :home_page_url, :string
|
|
@@ -578,11 +621,11 @@ class ExampleMigration < ActiveRecord::Migration
|
|
|
578
621
|
remove_column :users, :home_page_url
|
|
579
622
|
|
|
580
623
|
execute <<-SQL
|
|
581
|
-
ALTER TABLE
|
|
582
|
-
DROP
|
|
624
|
+
ALTER TABLE distributors
|
|
625
|
+
DROP CONSTRAINT zipchk
|
|
583
626
|
SQL
|
|
584
627
|
|
|
585
|
-
drop_table :
|
|
628
|
+
drop_table :distributors
|
|
586
629
|
end
|
|
587
630
|
end
|
|
588
631
|
```
|
|
@@ -613,43 +656,27 @@ end
|
|
|
613
656
|
The `revert` method also accepts a block of instructions to reverse.
|
|
614
657
|
This could be useful to revert selected parts of previous migrations.
|
|
615
658
|
For example, let's imagine that `ExampleMigration` is committed and it
|
|
616
|
-
is later decided it would be best to
|
|
617
|
-
|
|
659
|
+
is later decided it would be best to use Active Record validations,
|
|
660
|
+
in place of the `CHECK` constraint, to verify the zipcode.
|
|
618
661
|
|
|
619
662
|
```ruby
|
|
620
|
-
class
|
|
663
|
+
class DontUseConstraintForZipcodeValidationMigration < ActiveRecord::Migration
|
|
621
664
|
def change
|
|
622
|
-
add_column :categories, :product_list
|
|
623
|
-
|
|
624
|
-
reversible do |dir|
|
|
625
|
-
dir.up do
|
|
626
|
-
# transfer data from Products to Category#product_list
|
|
627
|
-
end
|
|
628
|
-
dir.down do
|
|
629
|
-
# create Products from Category#product_list
|
|
630
|
-
end
|
|
631
|
-
end
|
|
632
|
-
|
|
633
665
|
revert do
|
|
634
666
|
# copy-pasted code from ExampleMigration
|
|
635
|
-
create_table :products do |t|
|
|
636
|
-
t.references :category
|
|
637
|
-
end
|
|
638
|
-
|
|
639
667
|
reversible do |dir|
|
|
640
668
|
dir.up do
|
|
641
|
-
#add a
|
|
669
|
+
# add a CHECK constraint
|
|
642
670
|
execute <<-SQL
|
|
643
|
-
ALTER TABLE
|
|
644
|
-
ADD CONSTRAINT
|
|
645
|
-
|
|
646
|
-
REFERENCES categories(id)
|
|
671
|
+
ALTER TABLE distributors
|
|
672
|
+
ADD CONSTRAINT zipchk
|
|
673
|
+
CHECK (char_length(zipcode) = 5);
|
|
647
674
|
SQL
|
|
648
675
|
end
|
|
649
676
|
dir.down do
|
|
650
677
|
execute <<-SQL
|
|
651
|
-
ALTER TABLE
|
|
652
|
-
DROP
|
|
678
|
+
ALTER TABLE distributors
|
|
679
|
+
DROP CONSTRAINT zipchk
|
|
653
680
|
SQL
|
|
654
681
|
end
|
|
655
682
|
end
|
|
@@ -799,7 +826,7 @@ class CreateProducts < ActiveRecord::Migration
|
|
|
799
826
|
create_table :products do |t|
|
|
800
827
|
t.string :name
|
|
801
828
|
t.text :description
|
|
802
|
-
t.timestamps
|
|
829
|
+
t.timestamps null: false
|
|
803
830
|
end
|
|
804
831
|
end
|
|
805
832
|
|
|
@@ -853,159 +880,6 @@ The `revert` method can be helpful when writing a new migration to undo
|
|
|
853
880
|
previous migrations in whole or in part
|
|
854
881
|
(see [Reverting Previous Migrations](#reverting-previous-migrations) above).
|
|
855
882
|
|
|
856
|
-
Using Models in Your Migrations
|
|
857
|
-
-------------------------------
|
|
858
|
-
|
|
859
|
-
When creating or updating data in a migration it is often tempting to use one
|
|
860
|
-
of your models. After all, they exist to provide easy access to the underlying
|
|
861
|
-
data. This can be done, but some caution should be observed.
|
|
862
|
-
|
|
863
|
-
For example, problems occur when the model uses database columns which are (1)
|
|
864
|
-
not currently in the database and (2) will be created by this or a subsequent
|
|
865
|
-
migration.
|
|
866
|
-
|
|
867
|
-
Consider this example, where Alice and Bob are working on the same code base
|
|
868
|
-
which contains a `Product` model:
|
|
869
|
-
|
|
870
|
-
Bob goes on vacation.
|
|
871
|
-
|
|
872
|
-
Alice creates a migration for the `products` table which adds a new column and
|
|
873
|
-
initializes it:
|
|
874
|
-
|
|
875
|
-
```ruby
|
|
876
|
-
# db/migrate/20100513121110_add_flag_to_product.rb
|
|
877
|
-
|
|
878
|
-
class AddFlagToProduct < ActiveRecord::Migration
|
|
879
|
-
def change
|
|
880
|
-
add_column :products, :flag, :boolean
|
|
881
|
-
reversible do |dir|
|
|
882
|
-
dir.up { Product.update_all flag: false }
|
|
883
|
-
end
|
|
884
|
-
end
|
|
885
|
-
end
|
|
886
|
-
```
|
|
887
|
-
|
|
888
|
-
She also adds a validation to the `Product` model for the new column:
|
|
889
|
-
|
|
890
|
-
```ruby
|
|
891
|
-
# app/models/product.rb
|
|
892
|
-
|
|
893
|
-
class Product < ActiveRecord::Base
|
|
894
|
-
validates :flag, inclusion: { in: [true, false] }
|
|
895
|
-
end
|
|
896
|
-
```
|
|
897
|
-
|
|
898
|
-
Alice adds a second migration which adds another column to the `products`
|
|
899
|
-
table and initializes it:
|
|
900
|
-
|
|
901
|
-
```ruby
|
|
902
|
-
# db/migrate/20100515121110_add_fuzz_to_product.rb
|
|
903
|
-
|
|
904
|
-
class AddFuzzToProduct < ActiveRecord::Migration
|
|
905
|
-
def change
|
|
906
|
-
add_column :products, :fuzz, :string
|
|
907
|
-
reversible do |dir|
|
|
908
|
-
dir.up { Product.update_all fuzz: 'fuzzy' }
|
|
909
|
-
end
|
|
910
|
-
end
|
|
911
|
-
end
|
|
912
|
-
```
|
|
913
|
-
|
|
914
|
-
She also adds a validation to the `Product` model for the new column:
|
|
915
|
-
|
|
916
|
-
```ruby
|
|
917
|
-
# app/models/product.rb
|
|
918
|
-
|
|
919
|
-
class Product < ActiveRecord::Base
|
|
920
|
-
validates :flag, inclusion: { in: [true, false] }
|
|
921
|
-
validates :fuzz, presence: true
|
|
922
|
-
end
|
|
923
|
-
```
|
|
924
|
-
|
|
925
|
-
Both migrations work for Alice.
|
|
926
|
-
|
|
927
|
-
Bob comes back from vacation and:
|
|
928
|
-
|
|
929
|
-
* Updates the source - which contains both migrations and the latest version
|
|
930
|
-
of the Product model.
|
|
931
|
-
* Runs outstanding migrations with `rake db:migrate`, which
|
|
932
|
-
includes the one that updates the `Product` model.
|
|
933
|
-
|
|
934
|
-
The migration crashes because when the model attempts to save, it tries to
|
|
935
|
-
validate the second added column, which is not in the database when the _first_
|
|
936
|
-
migration runs:
|
|
937
|
-
|
|
938
|
-
```
|
|
939
|
-
rake aborted!
|
|
940
|
-
An error has occurred, this and all later migrations canceled:
|
|
941
|
-
|
|
942
|
-
undefined method `fuzz' for #<Product:0x000001049b14a0>
|
|
943
|
-
```
|
|
944
|
-
|
|
945
|
-
A fix for this is to create a local model within the migration. This keeps
|
|
946
|
-
Rails from running the validations, so that the migrations run to completion.
|
|
947
|
-
|
|
948
|
-
When using a local model, it's a good idea to call
|
|
949
|
-
`Product.reset_column_information` to refresh the Active Record cache for the
|
|
950
|
-
`Product` model prior to updating data in the database.
|
|
951
|
-
|
|
952
|
-
If Alice had done this instead, there would have been no problem:
|
|
953
|
-
|
|
954
|
-
```ruby
|
|
955
|
-
# db/migrate/20100513121110_add_flag_to_product.rb
|
|
956
|
-
|
|
957
|
-
class AddFlagToProduct < ActiveRecord::Migration
|
|
958
|
-
class Product < ActiveRecord::Base
|
|
959
|
-
end
|
|
960
|
-
|
|
961
|
-
def change
|
|
962
|
-
add_column :products, :flag, :boolean
|
|
963
|
-
Product.reset_column_information
|
|
964
|
-
reversible do |dir|
|
|
965
|
-
dir.up { Product.update_all flag: false }
|
|
966
|
-
end
|
|
967
|
-
end
|
|
968
|
-
end
|
|
969
|
-
```
|
|
970
|
-
|
|
971
|
-
```ruby
|
|
972
|
-
# db/migrate/20100515121110_add_fuzz_to_product.rb
|
|
973
|
-
|
|
974
|
-
class AddFuzzToProduct < ActiveRecord::Migration
|
|
975
|
-
class Product < ActiveRecord::Base
|
|
976
|
-
end
|
|
977
|
-
|
|
978
|
-
def change
|
|
979
|
-
add_column :products, :fuzz, :string
|
|
980
|
-
Product.reset_column_information
|
|
981
|
-
reversible do |dir|
|
|
982
|
-
dir.up { Product.update_all fuzz: 'fuzzy' }
|
|
983
|
-
end
|
|
984
|
-
end
|
|
985
|
-
end
|
|
986
|
-
```
|
|
987
|
-
|
|
988
|
-
There are other ways in which the above example could have gone badly.
|
|
989
|
-
|
|
990
|
-
For example, imagine that Alice creates a migration that selectively
|
|
991
|
-
updates the `description` field on certain products. She runs the
|
|
992
|
-
migration, commits the code, and then begins working on the next feature,
|
|
993
|
-
which is to add a new column `fuzz` to the products table.
|
|
994
|
-
|
|
995
|
-
She creates two migrations for this new feature, one which adds the new
|
|
996
|
-
column, and a second which selectively updates the `fuzz` column based on
|
|
997
|
-
other product attributes.
|
|
998
|
-
|
|
999
|
-
These migrations run just fine, but when Bob comes back from his vacation
|
|
1000
|
-
and calls `rake db:migrate` to run all the outstanding migrations, he gets a
|
|
1001
|
-
subtle bug: The descriptions have defaults, and the `fuzz` column is present,
|
|
1002
|
-
but `fuzz` is `nil` on all products.
|
|
1003
|
-
|
|
1004
|
-
The solution is again to use `Product.reset_column_information` before
|
|
1005
|
-
referencing the Product model in a migration, ensuring the Active Record's
|
|
1006
|
-
knowledge of the table structure is current before manipulating data in those
|
|
1007
|
-
records.
|
|
1008
|
-
|
|
1009
883
|
Schema Dumping and You
|
|
1010
884
|
----------------------
|
|
1011
885
|
|
|
@@ -1067,10 +941,10 @@ that Active Record supports. This could be very useful if you were to
|
|
|
1067
941
|
distribute an application that is able to run against multiple databases.
|
|
1068
942
|
|
|
1069
943
|
There is however a trade-off: `db/schema.rb` cannot express database specific
|
|
1070
|
-
items such as
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
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`.
|
|
1074
948
|
|
|
1075
949
|
Instead of using Active Record's schema dumper, the database's structure will
|
|
1076
950
|
be dumped using a tool specific to the database (via the `db:structure:dump`
|
|
@@ -1088,11 +962,16 @@ schema into a RDBMS other than the one used to create it.
|
|
|
1088
962
|
Because schema dumps are the authoritative source for your database schema, it
|
|
1089
963
|
is strongly recommended that you check them into source control.
|
|
1090
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
|
+
|
|
1091
970
|
Active Record and Referential Integrity
|
|
1092
971
|
---------------------------------------
|
|
1093
972
|
|
|
1094
973
|
The Active Record way claims that intelligence belongs in your models, not in
|
|
1095
|
-
the database. As such, features such as triggers or
|
|
974
|
+
the database. As such, features such as triggers or constraints,
|
|
1096
975
|
which push some of that intelligence back into the database, are not heavily
|
|
1097
976
|
used.
|
|
1098
977
|
|
|
@@ -1101,14 +980,10 @@ which models can enforce data integrity. The `:dependent` option on
|
|
|
1101
980
|
associations allows models to automatically destroy child objects when the
|
|
1102
981
|
parent is destroyed. Like anything which operates at the application level,
|
|
1103
982
|
these cannot guarantee referential integrity and so some people augment them
|
|
1104
|
-
with foreign key constraints in the database.
|
|
1105
|
-
|
|
1106
|
-
Although Active Record does not provide
|
|
1107
|
-
such features, the `execute` method can be used to execute arbitrary SQL.
|
|
1108
|
-
can also use a gem like
|
|
1109
|
-
[foreigner](https://github.com/matthuhiggins/foreigner) which adds foreign key
|
|
1110
|
-
support to Active Record (including support for dumping foreign keys in
|
|
1111
|
-
`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.
|
|
1112
987
|
|
|
1113
988
|
Migrations and Seed Data
|
|
1114
989
|
------------------------
|