railties 3.1.12 → 3.2.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +2292 -41
- data/README.rdoc +14 -5
- data/bin/rails +7 -0
- data/guides/code/getting_started/Gemfile +27 -0
- data/guides/code/getting_started/README.rdoc +261 -0
- data/guides/code/getting_started/Rakefile +7 -0
- data/guides/code/getting_started/app/assets/images/rails.png +0 -0
- data/guides/code/getting_started/app/assets/javascripts/application.js +9 -0
- data/guides/code/getting_started/app/assets/javascripts/comments.js.coffee +3 -0
- data/guides/code/getting_started/app/assets/javascripts/home.js.coffee +3 -0
- data/guides/code/getting_started/app/assets/javascripts/posts.js.coffee +3 -0
- data/guides/code/getting_started/app/assets/stylesheets/application.css +7 -0
- data/guides/code/getting_started/app/assets/stylesheets/comments.css.scss +3 -0
- data/guides/code/getting_started/app/assets/stylesheets/home.css.scss +3 -0
- data/guides/code/getting_started/app/assets/stylesheets/posts.css.scss +3 -0
- data/guides/code/getting_started/app/assets/stylesheets/scaffolds.css.scss +56 -0
- data/guides/code/getting_started/app/controllers/application_controller.rb +3 -0
- data/guides/code/getting_started/app/controllers/comments_controller.rb +16 -0
- data/guides/code/getting_started/app/controllers/home_controller.rb +5 -0
- data/guides/code/getting_started/app/controllers/posts_controller.rb +84 -0
- data/guides/code/getting_started/app/helpers/application_helper.rb +2 -0
- data/guides/code/getting_started/app/helpers/comments_helper.rb +2 -0
- data/guides/code/getting_started/app/helpers/home_helper.rb +2 -0
- data/guides/code/getting_started/app/helpers/posts_helper.rb +5 -0
- data/guides/code/getting_started/app/models/comment.rb +3 -0
- data/guides/code/getting_started/app/models/post.rb +11 -0
- data/guides/code/getting_started/app/models/tag.rb +3 -0
- data/guides/code/getting_started/app/views/comments/_comment.html.erb +15 -0
- data/guides/code/getting_started/app/views/comments/_form.html.erb +13 -0
- data/guides/code/getting_started/app/views/home/index.html.erb +2 -0
- data/guides/code/getting_started/app/views/layouts/application.html.erb +14 -0
- data/guides/code/getting_started/app/views/posts/_form.html.erb +32 -0
- data/guides/code/getting_started/app/views/posts/edit.html.erb +6 -0
- data/guides/code/getting_started/app/views/posts/index.html.erb +27 -0
- data/guides/code/getting_started/app/views/posts/new.html.erb +5 -0
- data/guides/code/getting_started/app/views/posts/show.html.erb +31 -0
- data/guides/code/getting_started/app/views/tags/_form.html.erb +12 -0
- data/guides/code/getting_started/config.ru +4 -0
- data/guides/code/getting_started/config/application.rb +53 -0
- data/guides/code/getting_started/config/boot.rb +6 -0
- data/guides/code/getting_started/config/database.yml +25 -0
- data/guides/code/getting_started/config/environment.rb +5 -0
- data/guides/code/getting_started/config/environments/development.rb +37 -0
- data/guides/code/getting_started/config/environments/production.rb +67 -0
- data/guides/code/getting_started/config/environments/test.rb +37 -0
- data/guides/code/getting_started/config/initializers/backtrace_silencers.rb +7 -0
- data/guides/code/getting_started/config/initializers/inflections.rb +10 -0
- data/guides/code/getting_started/config/initializers/mime_types.rb +5 -0
- data/guides/code/getting_started/config/initializers/secret_token.rb +7 -0
- data/guides/code/getting_started/config/initializers/session_store.rb +8 -0
- data/guides/code/getting_started/config/initializers/wrap_parameters.rb +14 -0
- data/guides/code/getting_started/config/locales/en.yml +5 -0
- data/guides/code/getting_started/config/routes.rb +64 -0
- data/guides/code/getting_started/db/migrate/20110901012504_create_posts.rb +11 -0
- data/guides/code/getting_started/db/migrate/20110901012815_create_comments.rb +12 -0
- data/guides/code/getting_started/db/migrate/20110901013701_create_tags.rb +11 -0
- data/guides/code/getting_started/db/schema.rb +43 -0
- data/guides/code/getting_started/db/seeds.rb +7 -0
- data/guides/code/getting_started/doc/README_FOR_APP +2 -0
- data/guides/code/getting_started/public/404.html +26 -0
- data/guides/code/getting_started/public/422.html +26 -0
- data/guides/code/getting_started/public/500.html +26 -0
- data/guides/code/getting_started/public/favicon.ico +0 -0
- data/guides/code/getting_started/public/robots.txt +5 -0
- data/guides/code/getting_started/script/rails +6 -0
- data/guides/code/getting_started/test/fixtures/comments.yml +11 -0
- data/guides/code/getting_started/test/fixtures/posts.yml +11 -0
- data/guides/code/getting_started/test/fixtures/tags.yml +9 -0
- data/guides/code/getting_started/test/functional/comments_controller_test.rb +7 -0
- data/guides/code/getting_started/test/functional/home_controller_test.rb +9 -0
- data/guides/code/getting_started/test/functional/posts_controller_test.rb +49 -0
- data/guides/code/getting_started/test/performance/browsing_test.rb +12 -0
- data/guides/code/getting_started/test/test_helper.rb +13 -0
- data/guides/code/getting_started/test/unit/comment_test.rb +7 -0
- data/guides/code/getting_started/test/unit/helpers/comments_helper_test.rb +4 -0
- data/guides/code/getting_started/test/unit/helpers/home_helper_test.rb +4 -0
- data/guides/code/getting_started/test/unit/helpers/posts_helper_test.rb +4 -0
- data/guides/code/getting_started/test/unit/post_test.rb +7 -0
- data/guides/code/getting_started/test/unit/tag_test.rb +7 -0
- data/guides/rails_guides/generator.rb +2 -1
- data/guides/source/3_0_release_notes.textile +2 -2
- data/guides/source/3_1_release_notes.textile +3 -110
- data/guides/source/action_controller_overview.textile +11 -13
- data/guides/source/action_mailer_basics.textile +7 -18
- data/guides/source/action_view_overview.textile +78 -9
- data/guides/source/active_model_basics.textile +205 -0
- data/guides/source/active_record_basics.textile +31 -31
- data/guides/source/active_record_querying.textile +288 -67
- data/guides/source/active_record_validations_callbacks.textile +69 -75
- data/guides/source/active_resource_basics.textile +48 -2
- data/guides/source/active_support_core_extensions.textile +145 -24
- data/guides/source/ajax_on_rails.textile +65 -7
- data/guides/source/api_documentation_guidelines.textile +0 -6
- data/guides/source/asset_pipeline.textile +2 -2
- data/guides/source/association_basics.textile +25 -34
- data/guides/source/caching_with_rails.textile +12 -17
- data/guides/source/command_line.textile +29 -19
- data/guides/source/configuring.textile +40 -18
- data/guides/source/contributing_to_ruby_on_rails.textile +11 -18
- data/guides/source/debugging_rails_applications.textile +10 -21
- data/guides/source/engines.textile +618 -0
- data/guides/source/form_helpers.textile +1 -12
- data/guides/source/generators.textile +9 -11
- data/guides/source/getting_started.textile +152 -152
- data/guides/source/i18n.textile +4 -5
- data/guides/source/index.html.erb +0 -1
- data/guides/source/initialization.textile +26 -26
- data/guides/source/layouts_and_rendering.textile +97 -61
- data/guides/source/migrations.textile +380 -161
- data/guides/source/performance_testing.textile +4 -10
- data/guides/source/plugins.textile +11 -19
- data/guides/source/rails_application_templates.textile +12 -4
- data/guides/source/rails_on_rack.textile +25 -19
- data/guides/source/routing.textile +6 -13
- data/guides/source/ruby_on_rails_guides_guidelines.textile +0 -5
- data/guides/source/security.textile +11 -15
- data/guides/source/testing.textile +1 -9
- data/lib/rails/application.rb +107 -42
- data/lib/rails/application/bootstrap.rb +12 -11
- data/lib/rails/application/configuration.rb +27 -21
- data/lib/rails/application/finisher.rb +40 -17
- data/lib/rails/application/route_inspector.rb +75 -0
- data/lib/rails/application/routes_reloader.rb +15 -4
- data/lib/rails/code_statistics.rb +16 -5
- data/lib/rails/commands.rb +6 -5
- data/lib/rails/commands/application.rb +8 -1
- data/lib/rails/commands/console.rb +2 -0
- data/lib/rails/commands/dbconsole.rb +2 -2
- data/lib/rails/commands/destroy.rb +0 -2
- data/lib/rails/commands/generate.rb +3 -3
- data/lib/rails/commands/plugin.rb +161 -159
- data/lib/rails/commands/plugin_new.rb +3 -2
- data/lib/rails/commands/runner.rb +4 -0
- data/lib/rails/console/app.rb +26 -22
- data/lib/rails/console/helpers.rb +9 -5
- data/lib/rails/engine.rb +70 -34
- data/lib/rails/engine/commands.rb +39 -0
- data/lib/rails/engine/configuration.rb +1 -1
- data/lib/rails/generators.rb +3 -14
- data/lib/rails/generators/actions.rb +36 -9
- data/lib/rails/generators/app_base.rb +34 -38
- data/lib/rails/generators/base.rb +4 -4
- data/lib/rails/generators/generated_attribute.rb +1 -1
- data/lib/rails/generators/named_base.rb +1 -3
- data/lib/rails/generators/rails/app/USAGE +6 -0
- data/lib/rails/generators/rails/app/app_generator.rb +6 -2
- data/lib/rails/generators/rails/app/templates/Gemfile +4 -3
- data/lib/rails/generators/rails/app/templates/app/assets/javascripts/application.js.tt +9 -3
- data/lib/rails/generators/rails/app/templates/app/assets/stylesheets/application.css +11 -5
- data/lib/rails/generators/rails/app/templates/app/mailers/.empty_directory +0 -0
- data/lib/rails/generators/rails/app/templates/app/models/.empty_directory +0 -0
- data/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt +1 -1
- data/lib/rails/generators/rails/app/templates/config/application.rb +11 -0
- data/lib/rails/generators/rails/app/templates/config/databases/jdbcpostgresql.yml +1 -1
- data/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml +1 -1
- data/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt +10 -1
- data/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt +10 -1
- data/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt +6 -6
- data/lib/rails/generators/rails/app/templates/config/initializers/inflections.rb +5 -0
- data/lib/rails/generators/rails/app/templates/config/routes.rb +1 -1
- data/lib/rails/generators/rails/app/templates/public/500.html +0 -1
- data/lib/rails/generators/rails/app/templates/public/index.html +1 -1
- data/lib/rails/generators/rails/app/templates/public/stylesheets/.empty_directory +0 -0
- data/lib/rails/generators/rails/app/templates/test/fixtures/.empty_directory +0 -0
- data/lib/rails/generators/rails/app/templates/test/functional/.empty_directory +0 -0
- data/lib/rails/generators/rails/app/templates/test/integration/.empty_directory +0 -0
- data/lib/rails/generators/rails/app/templates/test/unit/.empty_directory +0 -0
- data/lib/rails/generators/rails/controller/templates/controller.rb +1 -1
- data/lib/rails/generators/rails/generator/templates/templates/.empty_directory +0 -0
- data/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb +17 -5
- data/lib/rails/generators/rails/plugin_new/templates/Rakefile +1 -0
- data/lib/rails/generators/rails/plugin_new/templates/app/mailers/.empty_directory +0 -0
- data/lib/rails/generators/rails/plugin_new/templates/app/models/.empty_directory +0 -0
- data/lib/rails/generators/rails/plugin_new/templates/app/views/layouts/%name%/application.html.erb.tt +1 -1
- data/lib/rails/generators/rails/plugin_new/templates/gitignore +4 -3
- data/lib/rails/generators/rails/plugin_new/templates/lib/%name%/engine.rb +1 -1
- data/lib/rails/generators/rails/plugin_new/templates/rails/application.rb +1 -1
- data/lib/rails/generators/rails/plugin_new/templates/script/rails.tt +5 -3
- data/lib/rails/generators/rails/scaffold_controller/templates/controller.rb +2 -2
- data/lib/rails/generators/rails/task/USAGE +9 -0
- data/lib/rails/generators/rails/task/task_generator.rb +12 -0
- data/lib/rails/generators/rails/task/templates/task.rb +8 -0
- data/lib/rails/generators/resource_helpers.rb +3 -3
- data/lib/rails/generators/test_unit/integration/templates/integration_test.rb +0 -2
- data/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb +4 -4
- data/lib/rails/paths.rb +11 -38
- data/lib/rails/rack/debugger.rb +3 -4
- data/lib/rails/rack/logger.rb +26 -12
- data/lib/rails/railtie.rb +6 -1
- data/lib/rails/railtie/configuration.rb +12 -5
- data/lib/rails/source_annotation_extractor.rb +12 -10
- data/lib/rails/tasks/documentation.rake +3 -1
- data/lib/rails/tasks/engine.rake +1 -0
- data/lib/rails/tasks/misc.rake +1 -1
- data/lib/rails/tasks/routes.rake +3 -23
- data/lib/rails/test_help.rb +1 -2
- data/lib/rails/test_unit/testing.rake +8 -4
- data/lib/rails/version.rb +3 -3
- metadata +131 -61
- checksums.yaml +0 -7
- data/lib/rails/generators/rails/plugin/USAGE +0 -13
- data/lib/rails/generators/rails/plugin/plugin_generator.rb +0 -54
- data/lib/rails/generators/rails/plugin/templates/MIT-LICENSE.tt +0 -20
- data/lib/rails/generators/rails/plugin/templates/README.tt +0 -13
- data/lib/rails/generators/rails/plugin/templates/Rakefile.tt +0 -23
- data/lib/rails/generators/rails/plugin/templates/init.rb +0 -1
- data/lib/rails/generators/rails/plugin/templates/install.rb +0 -1
- data/lib/rails/generators/rails/plugin/templates/lib/%file_name%.rb.tt +0 -1
- data/lib/rails/generators/rails/plugin/templates/lib/tasks/%file_name%_tasks.rake.tt +0 -4
- data/lib/rails/generators/rails/plugin/templates/uninstall.rb +0 -1
@@ -1,12 +1,24 @@
|
|
1
1
|
h2. Migrations
|
2
2
|
|
3
|
-
Migrations are a convenient way for you to alter your database in a structured
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
3
|
+
Migrations are a convenient way for you to alter your database in a structured
|
4
|
+
and organized manner. You could edit fragments of SQL by hand but you would then
|
5
|
+
be responsible for telling other developers that they need to go and run them.
|
6
|
+
You'd also have to keep track of which changes need to be run against the
|
7
|
+
production machines next time you deploy.
|
8
|
+
|
9
|
+
Active Record tracks which migrations have already been run so all you have to
|
10
|
+
do is update your source and run +rake db:migrate+. Active Record will work out
|
11
|
+
which migrations should be run. It will also update your +db/schema.rb+ file to
|
12
|
+
match the structure of your database.
|
13
|
+
|
14
|
+
Migrations also allow you to describe these transformations using Ruby. The
|
15
|
+
great thing about this is that (like most of Active Record's functionality) it
|
16
|
+
is database independent: you don't need to worry about the precise syntax of
|
17
|
+
+CREATE TABLE+ any more than you worry about variations on +SELECT *+ (you can
|
18
|
+
drop down to raw SQL for database specific features). For example you could use
|
19
|
+
SQLite3 in development, but MySQL in production.
|
20
|
+
|
21
|
+
In this guide, you'll learn all about migrations including:
|
10
22
|
|
11
23
|
* The generators you can use to create them
|
12
24
|
* The methods Active Record provides to manipulate your database
|
@@ -17,7 +29,8 @@ endprologue.
|
|
17
29
|
|
18
30
|
h3. Anatomy of a Migration
|
19
31
|
|
20
|
-
Before we dive into the details of a migration, here are a few examples of the
|
32
|
+
Before we dive into the details of a migration, here are a few examples of the
|
33
|
+
sorts of things you can do:
|
21
34
|
|
22
35
|
<ruby>
|
23
36
|
class CreateProducts < ActiveRecord::Migration
|
@@ -36,9 +49,15 @@ class CreateProducts < ActiveRecord::Migration
|
|
36
49
|
end
|
37
50
|
</ruby>
|
38
51
|
|
39
|
-
This migration adds a table called +products+ with a string column called +name+
|
52
|
+
This migration adds a table called +products+ with a string column called +name+
|
53
|
+
and a text column called +description+. A primary key column called +id+ will
|
54
|
+
also be added, however since this is the default we do not need to ask for this.
|
55
|
+
The timestamp columns +created_at+ and +updated_at+ which Active Record
|
56
|
+
populates automatically will also be added. Reversing this migration is as
|
57
|
+
simple as dropping the table.
|
40
58
|
|
41
|
-
Migrations are not limited to changing the schema. You can also use them to fix
|
59
|
+
Migrations are not limited to changing the schema. You can also use them to fix
|
60
|
+
bad data in the database or populate new fields:
|
42
61
|
|
43
62
|
<ruby>
|
44
63
|
class AddReceiveNewsletterToUsers < ActiveRecord::Migration
|
@@ -55,12 +74,18 @@ class AddReceiveNewsletterToUsers < ActiveRecord::Migration
|
|
55
74
|
end
|
56
75
|
</ruby>
|
57
76
|
|
58
|
-
NOTE: Some "caveats":#using-models-in-your-migrations apply to using models in
|
77
|
+
NOTE: Some "caveats":#using-models-in-your-migrations apply to using models in
|
78
|
+
your migrations.
|
59
79
|
|
60
|
-
This migration adds a +receive_newsletter+ column to the +users+ table. We want
|
61
|
-
to
|
80
|
+
This migration adds a +receive_newsletter+ column to the +users+ table. We want
|
81
|
+
it to default to +false+ for new users, but existing users are considered to
|
82
|
+
have already opted in, so we use the User model to set the flag to +true+ for
|
83
|
+
existing users.
|
62
84
|
|
63
|
-
Rails 3.1 makes migrations smarter by providing a new <tt>change</tt> method.
|
85
|
+
Rails 3.1 makes migrations smarter by providing a new <tt>change</tt> method.
|
86
|
+
This method is preferred for writing constructive migrations (adding columns or
|
87
|
+
tables). The migration knows how to migrate your database and reverse it when
|
88
|
+
the migration is rolled back without the need to write a separate +down+ method.
|
64
89
|
|
65
90
|
<ruby>
|
66
91
|
class CreateProducts < ActiveRecord::Migration
|
@@ -77,64 +102,111 @@ end
|
|
77
102
|
|
78
103
|
h4. Migrations are Classes
|
79
104
|
|
80
|
-
A migration is a subclass of <tt>ActiveRecord::Migration</tt> that implements
|
105
|
+
A migration is a subclass of <tt>ActiveRecord::Migration</tt> that implements
|
106
|
+
two methods: +up+ (perform the required transformations) and +down+ (revert
|
107
|
+
them).
|
81
108
|
|
82
|
-
Active Record provides methods that perform common data definition tasks in a
|
109
|
+
Active Record provides methods that perform common data definition tasks in a
|
110
|
+
database independent way (you'll read about them in detail later):
|
83
111
|
|
84
|
-
* +create_table+
|
85
|
-
* +change_table+
|
86
|
-
* +drop_table+
|
87
112
|
* +add_column+
|
113
|
+
* +add_index+
|
88
114
|
* +change_column+
|
89
|
-
* +
|
115
|
+
* +change_table+
|
116
|
+
* +create_table+
|
117
|
+
* +drop_table+
|
90
118
|
* +remove_column+
|
91
|
-
* +add_index+
|
92
119
|
* +remove_index+
|
120
|
+
* +rename_column+
|
93
121
|
|
94
|
-
If you need to perform tasks specific to your database (for example create a
|
122
|
+
If you need to perform tasks specific to your database (for example create a
|
123
|
+
"foreign key":#active-record-and-referential-integrity constraint) then the
|
124
|
+
+execute+ method allows you to execute arbitrary SQL. A migration is just a
|
125
|
+
regular Ruby class so you're not limited to these functions. For example after
|
126
|
+
adding a column you could write code to set the value of that column for
|
127
|
+
existing records (if necessary using your models).
|
95
128
|
|
96
|
-
On databases that support transactions with statements that change the schema
|
129
|
+
On databases that support transactions with statements that change the schema
|
130
|
+
(such as PostgreSQL or SQLite3), migrations are wrapped in a transaction. If the
|
131
|
+
database does not support this (for example MySQL) then when a migration fails
|
132
|
+
the parts of it that succeeded will not be rolled back. You will have to rollback
|
133
|
+
the changes that were made by hand.
|
97
134
|
|
98
135
|
h4. What's in a Name
|
99
136
|
|
100
|
-
Migrations are stored
|
101
|
-
|
102
|
-
|
137
|
+
Migrations are stored as files in the +db/migrate+ directory, one for each
|
138
|
+
migration class. The name of the file is of the form
|
139
|
+
+YYYYMMDDHHMMSS_create_products.rb+, that is to say a UTC timestamp
|
140
|
+
identifying the migration followed by an underscore followed by the name
|
141
|
+
of the migration. The name of the migration class (CamelCased version)
|
142
|
+
should match the latter part of the file name. For example
|
143
|
+
+20080906120000_create_products.rb+ should define class +CreateProducts+ and
|
144
|
+
+20080906120001_add_details_to_products.rb+ should define
|
145
|
+
+AddDetailsToProducts+. If you do feel the need to change the file name then you
|
146
|
+
<em>have to</em> update the name of the class inside or Rails will complain
|
147
|
+
about a missing class.
|
148
|
+
|
149
|
+
Internally Rails only uses the migration's number (the timestamp) to identify
|
150
|
+
them. Prior to Rails 2.1 the migration number started at 1 and was incremented
|
151
|
+
each time a migration was generated. With multiple developers it was easy for
|
152
|
+
these to clash requiring you to rollback migrations and renumber them. With
|
153
|
+
Rails 2.1+ this is largely avoided by using the creation time of the migration
|
154
|
+
to identify them. You can revert to the old numbering scheme by adding the
|
155
|
+
following line to +config/application.rb+.
|
103
156
|
|
104
157
|
<ruby>
|
105
158
|
config.active_record.timestamped_migrations = false
|
106
159
|
</ruby>
|
107
160
|
|
108
|
-
The combination of timestamps and recording which migrations have been run
|
161
|
+
The combination of timestamps and recording which migrations have been run
|
162
|
+
allows Rails to handle common situations that occur with multiple developers.
|
109
163
|
|
110
|
-
For example Alice adds migrations +20080906120000+ and +20080906123000+ and Bob
|
164
|
+
For example Alice adds migrations +20080906120000+ and +20080906123000+ and Bob
|
165
|
+
adds +20080906124500+ and runs it. Alice finishes her changes and checks in her
|
166
|
+
migrations and Bob pulls down the latest changes. When Bob runs +rake db:migrate+,
|
167
|
+
Rails knows that it has not run Alice's two migrations so it executes the +up+ method for each migration.
|
111
168
|
|
112
|
-
Of course this is no substitution for communication within the team. For
|
169
|
+
Of course this is no substitution for communication within the team. For
|
170
|
+
example, if Alice's migration removed a table that Bob's migration assumed to
|
171
|
+
exist, then trouble would certainly strike.
|
113
172
|
|
114
173
|
h4. Changing Migrations
|
115
174
|
|
116
|
-
Occasionally you will make a mistake when writing a migration. If you have
|
175
|
+
Occasionally you will make a mistake when writing a migration. If you have
|
176
|
+
already run the migration then you cannot just edit the migration and run the
|
177
|
+
migration again: Rails thinks it has already run the migration and so will do
|
178
|
+
nothing when you run +rake db:migrate+. You must rollback the migration (for
|
179
|
+
example with +rake db:rollback+), edit your migration and then run +rake db:migrate+ to run the corrected version.
|
117
180
|
|
118
|
-
In general editing existing migrations is not a good idea: you will be creating
|
181
|
+
In general editing existing migrations is not a good idea: you will be creating
|
182
|
+
extra work for yourself and your co-workers and cause major headaches if the
|
183
|
+
existing version of the migration has already been run on production machines.
|
184
|
+
Instead, you should write a new migration that performs the changes you require.
|
185
|
+
Editing a freshly generated migration that has not yet been committed to source
|
186
|
+
control (or, more generally, which has not been propagated beyond your
|
187
|
+
development machine) is relatively harmless.
|
119
188
|
|
120
189
|
h4. Supported Types
|
121
190
|
|
122
|
-
Active Record supports the following types:
|
191
|
+
Active Record supports the following database column types:
|
123
192
|
|
193
|
+
* +:binary+
|
194
|
+
* +:boolean+
|
195
|
+
* +:date+
|
196
|
+
* +:datetime+
|
197
|
+
* +:decimal+
|
198
|
+
* +:float+
|
199
|
+
* +:integer+
|
124
200
|
* +:primary_key+
|
125
201
|
* +:string+
|
126
202
|
* +:text+
|
127
|
-
* +:integer+
|
128
|
-
* +:float+
|
129
|
-
* +:decimal+
|
130
|
-
* +:datetime+
|
131
|
-
* +:timestamp+
|
132
203
|
* +:time+
|
133
|
-
* +:
|
134
|
-
* +:binary+
|
135
|
-
* +:boolean+
|
204
|
+
* +:timestamp+
|
136
205
|
|
137
|
-
These will be mapped onto an appropriate underlying database type
|
206
|
+
These will be mapped onto an appropriate underlying database type. For example,
|
207
|
+
with MySQL the type +:string+ is mapped to +VARCHAR(255)+. You can create
|
208
|
+
columns of types not supported by Active Record when using the non-sexy syntax,
|
209
|
+
for example
|
138
210
|
|
139
211
|
<ruby>
|
140
212
|
create_table :products do |t|
|
@@ -148,7 +220,10 @@ h3. Creating a Migration
|
|
148
220
|
|
149
221
|
h4. Creating a Model
|
150
222
|
|
151
|
-
The model and scaffold generators will create migrations appropriate for adding
|
223
|
+
The model and scaffold generators will create migrations appropriate for adding
|
224
|
+
a new model. This migration will already contain instructions for creating the
|
225
|
+
relevant table. If you tell Rails what columns you want, then statements for
|
226
|
+
adding these columns will also be created. For example, running
|
152
227
|
|
153
228
|
<shell>
|
154
229
|
$ rails generate model Product name:string description:text
|
@@ -169,12 +244,15 @@ class CreateProducts < ActiveRecord::Migration
|
|
169
244
|
end
|
170
245
|
</ruby>
|
171
246
|
|
172
|
-
You can append as many column name/type pairs as you want. By default
|
173
|
-
|
247
|
+
You can append as many column name/type pairs as you want. By default, the
|
248
|
+
generated migration will include +t.timestamps+ (which creates the
|
249
|
+
+updated_at+ and +created_at+ columns that are automatically populated
|
250
|
+
by Active Record).
|
174
251
|
|
175
252
|
h4. Creating a Standalone Migration
|
176
253
|
|
177
|
-
If you are creating migrations for other purposes (for example to add a column
|
254
|
+
If you are creating migrations for other purposes (for example to add a column
|
255
|
+
to an existing table) then you can also use the migration generator:
|
178
256
|
|
179
257
|
<shell>
|
180
258
|
$ rails generate migration AddPartNumberToProducts
|
@@ -189,7 +267,9 @@ class AddPartNumberToProducts < ActiveRecord::Migration
|
|
189
267
|
end
|
190
268
|
</ruby>
|
191
269
|
|
192
|
-
If the migration name is of the form "AddXXXToYYY" or "RemoveXXXFromYYY" and is
|
270
|
+
If the migration name is of the form "AddXXXToYYY" or "RemoveXXXFromYYY" and is
|
271
|
+
followed by a list of column names and types then a migration containing the
|
272
|
+
appropriate +add_column+ and +remove_column+ statements will be created.
|
193
273
|
|
194
274
|
<shell>
|
195
275
|
$ rails generate migration AddPartNumberToProducts part_number:string
|
@@ -242,17 +322,23 @@ class AddDetailsToProducts < ActiveRecord::Migration
|
|
242
322
|
end
|
243
323
|
</ruby>
|
244
324
|
|
245
|
-
As always, what has been generated for you is just a starting point. You can add
|
325
|
+
As always, what has been generated for you is just a starting point. You can add
|
326
|
+
or remove from it as you see fit by editing the
|
327
|
+
db/migrate/YYYYMMDDHHMMSS_add_details_to_products.rb file.
|
246
328
|
|
247
|
-
NOTE: The generated migration file for destructive migrations will still be
|
329
|
+
NOTE: The generated migration file for destructive migrations will still be
|
330
|
+
old-style using the +up+ and +down+ methods. This is because Rails needs to know
|
331
|
+
the original data types defined when you made the original changes.
|
248
332
|
|
249
333
|
h3. Writing a Migration
|
250
334
|
|
251
|
-
Once you have created your migration using one of the generators it's time to
|
335
|
+
Once you have created your migration using one of the generators it's time to
|
336
|
+
get to work!
|
252
337
|
|
253
338
|
h4. Creating a Table
|
254
339
|
|
255
|
-
Migration method +create_table+ will be one of your workhorses. A typical use
|
340
|
+
Migration method +create_table+ will be one of your workhorses. A typical use
|
341
|
+
would be
|
256
342
|
|
257
343
|
<ruby>
|
258
344
|
create_table :products do |t|
|
@@ -260,9 +346,11 @@ create_table :products do |t|
|
|
260
346
|
end
|
261
347
|
</ruby>
|
262
348
|
|
263
|
-
which creates a +products+ table with a column called +name+ (and as discussed
|
349
|
+
which creates a +products+ table with a column called +name+ (and as discussed
|
350
|
+
below, an implicit +id+ column).
|
264
351
|
|
265
|
-
The object yielded to the block allows you to create columns on the table. There
|
352
|
+
The object yielded to the block allows you to create columns on the table. There
|
353
|
+
are two ways of doing it. The first (traditional) form looks like
|
266
354
|
|
267
355
|
<ruby>
|
268
356
|
create_table :products do |t|
|
@@ -270,7 +358,9 @@ create_table :products do |t|
|
|
270
358
|
end
|
271
359
|
</ruby>
|
272
360
|
|
273
|
-
|
361
|
+
The second form, the so called "sexy" migration, drops the somewhat redundant
|
362
|
+
+column+ method. Instead, the +string+, +integer+, etc. methods create a column
|
363
|
+
of that type. Subsequent parameters are the same.
|
274
364
|
|
275
365
|
<ruby>
|
276
366
|
create_table :products do |t|
|
@@ -278,7 +368,12 @@ create_table :products do |t|
|
|
278
368
|
end
|
279
369
|
</ruby>
|
280
370
|
|
281
|
-
By default +create_table+ will create a primary key called +id+. You can change
|
371
|
+
By default, +create_table+ will create a primary key called +id+. You can change
|
372
|
+
the name of the primary key with the +:primary_key+ option (don't forget to
|
373
|
+
update the corresponding model) or, if you don't want a primary key at all (for
|
374
|
+
example for a HABTM join table), you can pass the option +:id => false+. If you
|
375
|
+
need to pass database specific options you can place an SQL fragment in the
|
376
|
+
+:options+ option. For example,
|
282
377
|
|
283
378
|
<ruby>
|
284
379
|
create_table :products, :options => "ENGINE=BLACKHOLE" do |t|
|
@@ -286,11 +381,14 @@ create_table :products, :options => "ENGINE=BLACKHOLE" do |t|
|
|
286
381
|
end
|
287
382
|
</ruby>
|
288
383
|
|
289
|
-
will append +ENGINE=BLACKHOLE+ to the SQL statement used to create the table
|
384
|
+
will append +ENGINE=BLACKHOLE+ to the SQL statement used to create the table
|
385
|
+
(when using MySQL, the default is +ENGINE=InnoDB+).
|
290
386
|
|
291
387
|
h4. Changing Tables
|
292
388
|
|
293
|
-
A close cousin of +create_table+ is +change_table+, used for changing existing
|
389
|
+
A close cousin of +create_table+ is +change_table+, used for changing existing
|
390
|
+
tables. It is used in a similar fashion to +create_table+ but the object yielded
|
391
|
+
to the block knows more tricks. For example
|
294
392
|
|
295
393
|
<ruby>
|
296
394
|
change_table :products do |t|
|
@@ -301,28 +399,23 @@ change_table :products do |t|
|
|
301
399
|
end
|
302
400
|
</ruby>
|
303
401
|
|
304
|
-
removes the +description+ and +name+ columns, creates a +part_number+
|
305
|
-
|
306
|
-
<ruby>
|
307
|
-
remove_column :products, :description
|
308
|
-
remove_column :products, :name
|
309
|
-
add_column :products, :part_number, :string
|
310
|
-
add_index :products, :part_number
|
311
|
-
rename_column :products, :upccode, :upc_code
|
312
|
-
</ruby>
|
313
|
-
|
314
|
-
You don't have to keep repeating the table name and it groups all the statements related to modifying one particular table. The individual transformation names are also shorter, for example +remove_column+ becomes just +remove+ and +add_index+ becomes just +index+.
|
402
|
+
removes the +description+ and +name+ columns, creates a +part_number+ string
|
403
|
+
column and adds an index on it. Finally it renames the +upccode+ column.
|
315
404
|
|
316
405
|
h4. Special Helpers
|
317
406
|
|
318
|
-
Active Record provides some shortcuts for common functionality. It is for
|
407
|
+
Active Record provides some shortcuts for common functionality. It is for
|
408
|
+
example very common to add both the +created_at+ and +updated_at+ columns and so
|
409
|
+
there is a method that does exactly that:
|
319
410
|
|
320
411
|
<ruby>
|
321
412
|
create_table :products do |t|
|
322
413
|
t.timestamps
|
323
414
|
end
|
324
415
|
</ruby>
|
325
|
-
|
416
|
+
|
417
|
+
will create a new products table with those two columns (plus the +id+ column)
|
418
|
+
whereas
|
326
419
|
|
327
420
|
<ruby>
|
328
421
|
change_table :products do |t|
|
@@ -331,7 +424,8 @@ end
|
|
331
424
|
</ruby>
|
332
425
|
adds those columns to an existing table.
|
333
426
|
|
334
|
-
|
427
|
+
Another helper is called +references+ (also available as +belongs_to+). In its
|
428
|
+
simplest form it just adds some readability.
|
335
429
|
|
336
430
|
<ruby>
|
337
431
|
create_table :products do |t|
|
@@ -339,24 +433,42 @@ create_table :products do |t|
|
|
339
433
|
end
|
340
434
|
</ruby>
|
341
435
|
|
342
|
-
will create a +category_id+ column of the appropriate type. Note that you pass
|
436
|
+
will create a +category_id+ column of the appropriate type. Note that you pass
|
437
|
+
the model name, not the column name. Active Record adds the +_id+ for you. If
|
438
|
+
you have polymorphic +belongs_to+ associations then +references+ will add both
|
439
|
+
of the columns required:
|
343
440
|
|
344
441
|
<ruby>
|
345
442
|
create_table :products do |t|
|
346
443
|
t.references :attachment, :polymorphic => {:default => 'Photo'}
|
347
444
|
end
|
348
445
|
</ruby>
|
349
|
-
will add an +attachment_id+ column and a string +attachment_type+ column with a default value of 'Photo'.
|
350
446
|
|
351
|
-
|
447
|
+
will add an +attachment_id+ column and a string +attachment_type+ column with
|
448
|
+
a default value of 'Photo'.
|
449
|
+
|
450
|
+
NOTE: The +references+ helper does not actually create foreign key constraints
|
451
|
+
for you. You will need to use +execute+ or a plugin that adds "foreign key
|
452
|
+
support":#active-record-and-referential-integrity.
|
352
453
|
|
353
|
-
If the helpers provided by Active Record aren't enough you can use the +execute+
|
454
|
+
If the helpers provided by Active Record aren't enough you can use the +execute+
|
455
|
+
method to execute arbitrary SQL.
|
354
456
|
|
355
|
-
For more details and examples of individual methods check the API documentation,
|
457
|
+
For more details and examples of individual methods, check the API documentation,
|
458
|
+
in particular the documentation for
|
459
|
+
"<tt>ActiveRecord::ConnectionAdapters::SchemaStatements</tt>":http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html
|
460
|
+
(which provides the methods available in the +up+ and +down+ methods),
|
461
|
+
"<tt>ActiveRecord::ConnectionAdapters::TableDefinition</tt>":http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/TableDefinition.html
|
462
|
+
(which provides the methods available on the object yielded by +create_table+)
|
463
|
+
and
|
464
|
+
"<tt>ActiveRecord::ConnectionAdapters::Table</tt>":http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/Table.html
|
465
|
+
(which provides the methods available on the object yielded by +change_table+).
|
356
466
|
|
357
|
-
h4.
|
467
|
+
h4. Using the +change+ Method
|
358
468
|
|
359
|
-
The +change+ method removes the need to write both +up+ and +down+ methods in
|
469
|
+
The +change+ method removes the need to write both +up+ and +down+ methods in
|
470
|
+
those cases that Rails know how to revert the changes automatically. Currently,
|
471
|
+
the +change+ method supports only these migration definitions:
|
360
472
|
|
361
473
|
* +add_column+
|
362
474
|
* +add_index+
|
@@ -367,15 +479,20 @@ The +change+ method removes the need to write both +up+ and +down+ methods in th
|
|
367
479
|
* +rename_index+
|
368
480
|
* +rename_table+
|
369
481
|
|
370
|
-
If you're going to use other methods, you'll have to write the
|
482
|
+
If you're going to need to use any other methods, you'll have to write the
|
483
|
+
+up+ and +down+ methods instead of using the +change+ method.
|
371
484
|
|
372
|
-
h4.
|
485
|
+
h4. Using the +up+/+down+ Methods
|
373
486
|
|
374
|
-
The +down+ method of your migration should revert the transformations done by
|
487
|
+
The +down+ method of your migration should revert the transformations done by
|
488
|
+
the +up+ method. In other words, the database schema should be unchanged if you
|
489
|
+
do an +up+ followed by a +down+. For example, if you create a table in the +up+
|
490
|
+
method, you should drop it in the +down+ method. It is wise to reverse the
|
491
|
+
transformations in precisely the reverse order they were made in the +up+
|
492
|
+
method. For example,
|
375
493
|
|
376
494
|
<ruby>
|
377
495
|
class ExampleMigration < ActiveRecord::Migration
|
378
|
-
|
379
496
|
def up
|
380
497
|
create_table :products do |t|
|
381
498
|
t.references :category
|
@@ -387,47 +504,69 @@ class ExampleMigration < ActiveRecord::Migration
|
|
387
504
|
FOREIGN KEY (category_id)
|
388
505
|
REFERENCES categories(id)
|
389
506
|
SQL
|
390
|
-
|
391
507
|
add_column :users, :home_page_url, :string
|
392
|
-
|
393
508
|
rename_column :users, :email, :email_address
|
394
509
|
end
|
395
510
|
|
396
511
|
def down
|
397
512
|
rename_column :users, :email_address, :email
|
398
513
|
remove_column :users, :home_page_url
|
399
|
-
execute
|
514
|
+
execute <<-SQL
|
515
|
+
ALTER TABLE products
|
516
|
+
DROP FOREIGN KEY fk_products_categories
|
517
|
+
SQL
|
400
518
|
drop_table :products
|
401
519
|
end
|
402
520
|
end
|
403
521
|
</ruby>
|
404
522
|
|
405
|
-
Sometimes your migration will do something which is just plain irreversible
|
523
|
+
Sometimes your migration will do something which is just plain irreversible; for
|
524
|
+
example, it might destroy some data. In such cases, you can raise
|
525
|
+
+ActiveRecord::IrreversibleMigration+ from your +down+ method. If someone tries
|
526
|
+
to revert your migration, an error message will be displayed saying that it
|
527
|
+
can't be done.
|
406
528
|
|
407
529
|
h3. Running Migrations
|
408
530
|
|
409
|
-
Rails provides a set of rake tasks to work with migrations which
|
531
|
+
Rails provides a set of rake tasks to work with migrations which boil down to
|
532
|
+
running certain sets of migrations.
|
533
|
+
|
534
|
+
The very first migration related rake task you will use will probably be
|
535
|
+
+rake db:migrate+. In its most basic form it just runs the +up+ or +change+
|
536
|
+
method for all the migrations that have not yet been run. If there are
|
537
|
+
no such migrations, it exits. It will run these migrations in order based
|
538
|
+
on the date of the migration.
|
410
539
|
|
411
|
-
Note that running the +db:migrate+ also invokes the +db:schema:dump+ task, which
|
540
|
+
Note that running the +db:migrate+ also invokes the +db:schema:dump+ task, which
|
541
|
+
will update your db/schema.rb file to match the structure of your database.
|
412
542
|
|
413
|
-
If you specify a target version, Active Record will run the required migrations
|
414
|
-
|
543
|
+
If you specify a target version, Active Record will run the required migrations
|
544
|
+
(up, down or change) until it has reached the specified version. The version
|
545
|
+
is the numerical prefix on the migration's filename. For example, to migrate
|
546
|
+
to version 20080906120000 run
|
415
547
|
|
416
548
|
<shell>
|
417
549
|
$ rake db:migrate VERSION=20080906120000
|
418
550
|
</shell>
|
419
551
|
|
420
|
-
If
|
552
|
+
If version 20080906120000 is greater than the current version (i.e., it is
|
553
|
+
migrating upwards), this will run the +up+ method on all migrations up to and
|
554
|
+
including 20080906120000, and will not execute any later migrations. If
|
555
|
+
migrating downwards, this will run the +down+ method on all the migrations
|
556
|
+
down to, but not including, 20080906120000.
|
421
557
|
|
422
558
|
h4. Rolling Back
|
423
559
|
|
424
|
-
A common task is to rollback the last migration, for example if you made a
|
560
|
+
A common task is to rollback the last migration, for example if you made a
|
561
|
+
mistake in it and wish to correct it. Rather than tracking down the version
|
562
|
+
number associated with the previous migration you can run
|
425
563
|
|
426
564
|
<shell>
|
427
565
|
$ rake db:rollback
|
428
566
|
</shell>
|
429
567
|
|
430
|
-
This will run the +down+ method from the latest migration. If you need to undo
|
568
|
+
This will run the +down+ method from the latest migration. If you need to undo
|
569
|
+
several migrations you can provide a +STEP+ parameter:
|
431
570
|
|
432
571
|
<shell>
|
433
572
|
$ rake db:rollback STEP=3
|
@@ -435,46 +574,65 @@ $ rake db:rollback STEP=3
|
|
435
574
|
|
436
575
|
will run the +down+ method from the last 3 migrations.
|
437
576
|
|
438
|
-
The +db:migrate:redo+ task is a shortcut for doing a rollback and then migrating
|
577
|
+
The +db:migrate:redo+ task is a shortcut for doing a rollback and then migrating
|
578
|
+
back up again. As with the +db:rollback+ task, you can use the +STEP+ parameter
|
579
|
+
if you need to go more than one version back, for example
|
439
580
|
|
440
581
|
<shell>
|
441
582
|
$ rake db:migrate:redo STEP=3
|
442
583
|
</shell>
|
443
584
|
|
444
|
-
Neither of these Rake tasks do anything you could not do with +db:migrate
|
585
|
+
Neither of these Rake tasks do anything you could not do with +db:migrate+. They
|
586
|
+
are simply more convenient, since you do not need to explicitly specify the
|
587
|
+
version to migrate to.
|
445
588
|
|
446
|
-
|
589
|
+
h4. Resetting the database
|
447
590
|
|
448
|
-
|
591
|
+
The +rake db:reset+ task will drop the database, recreate it and load the
|
592
|
+
current schema into it.
|
449
593
|
|
450
|
-
|
594
|
+
NOTE: This is not the same as running all the migrations - see the section on
|
595
|
+
"schema.rb":#schema-dumping-and-you.
|
451
596
|
|
452
|
-
|
597
|
+
h4. Running specific migrations
|
598
|
+
|
599
|
+
If you need to run a specific migration up or down, the +db:migrate:up+ and
|
600
|
+
+db:migrate:down+ tasks will do that. Just specify the appropriate version and
|
601
|
+
the corresponding migration will have its +up+ or +down+ method invoked, for
|
602
|
+
example,
|
453
603
|
|
454
604
|
<shell>
|
455
605
|
$ rake db:migrate:up VERSION=20080906120000
|
456
606
|
</shell>
|
457
607
|
|
458
|
-
will run the +up+ method from the 20080906120000 migration. These tasks
|
608
|
+
will run the +up+ method from the 20080906120000 migration. These tasks still
|
609
|
+
check whether the migration has already run, so for example +db:migrate:up
|
610
|
+
VERSION=20080906120000+ will do nothing if Active Record believes that
|
611
|
+
20080906120000 has already been run.
|
459
612
|
|
460
|
-
h4.
|
613
|
+
h4. Changing the output of running migrations
|
461
614
|
|
462
|
-
By default migrations tell you exactly what they're doing and how long it took.
|
615
|
+
By default migrations tell you exactly what they're doing and how long it took.
|
616
|
+
A migration creating a table and adding an index might produce output like this
|
463
617
|
|
464
618
|
<shell>
|
465
|
-
|
619
|
+
== CreateProducts: migrating =================================================
|
466
620
|
-- create_table(:products)
|
467
|
-
-> 0.
|
468
|
-
|
469
|
-
-> 0.0026s
|
470
|
-
20080906170109 CreateProducts: migrated (0.0059s)
|
621
|
+
-> 0.0028s
|
622
|
+
== CreateProducts: migrated (0.0028s) ========================================
|
471
623
|
</shell>
|
472
624
|
|
473
|
-
Several methods are provided that allow you to control all this:
|
625
|
+
Several methods are provided in migrations that allow you to control all this:
|
474
626
|
|
475
|
-
|
476
|
-
|
477
|
-
|
627
|
+
|_.Method |_.Purpose|
|
628
|
+
|suppress_messages |Takes a block as an argument and suppresses any output
|
629
|
+
generated by the block.|
|
630
|
+
|say |Takes a message argument and outputs it as is. A second
|
631
|
+
boolean argument can be passed to specify whether to
|
632
|
+
indent or not.|
|
633
|
+
|say_with_time |Outputs text along with how long it took to run its
|
634
|
+
block. If the block returns an integer it assumes it
|
635
|
+
is the number of rows affected.|
|
478
636
|
|
479
637
|
For example, this migration
|
480
638
|
|
@@ -502,37 +660,46 @@ end
|
|
502
660
|
generates the following output
|
503
661
|
|
504
662
|
<shell>
|
505
|
-
|
506
|
-
|
663
|
+
== CreateProducts: migrating =================================================
|
664
|
+
-- Created a table
|
507
665
|
-> and an index!
|
508
|
-
|
509
|
-
-> 10.
|
666
|
+
-- Waiting for a while
|
667
|
+
-> 10.0013s
|
510
668
|
-> 250 rows
|
511
|
-
|
669
|
+
== CreateProducts: migrated (10.0054s) =======================================
|
512
670
|
</shell>
|
513
671
|
|
514
|
-
If you
|
672
|
+
If you want Active Record to not output anything, then running +rake db:migrate
|
673
|
+
VERBOSE=false+ will suppress all output.
|
515
674
|
|
516
675
|
h3. Using Models in Your Migrations
|
517
676
|
|
518
|
-
When creating or updating data in a migration it is often tempting to use one of
|
677
|
+
When creating or updating data in a migration it is often tempting to use one of
|
678
|
+
your models. After all, they exist to provide easy access to the underlying
|
679
|
+
data. This can be done, but some caution should be observed.
|
519
680
|
|
520
|
-
For example, problems occur when the model uses database columns which are (1)
|
681
|
+
For example, problems occur when the model uses database columns which are (1)
|
682
|
+
not currently in the database and (2) will be created by this or a subsequent
|
683
|
+
migration.
|
521
684
|
|
522
|
-
Consider this example, where Alice and Bob are working on the same code base
|
685
|
+
Consider this example, where Alice and Bob are working on the same code base
|
686
|
+
which contains a +Product+ model:
|
523
687
|
|
524
688
|
Bob goes on vacation.
|
525
689
|
|
526
|
-
Alice creates a migration for the +products+ table which adds a new column and
|
527
|
-
She also adds a validation to the Product model for the new
|
690
|
+
Alice creates a migration for the +products+ table which adds a new column and
|
691
|
+
initializes it. She also adds a validation to the +Product+ model for the new
|
692
|
+
column.
|
528
693
|
|
529
694
|
<ruby>
|
530
695
|
# db/migrate/20100513121110_add_flag_to_product.rb
|
531
696
|
|
532
697
|
class AddFlagToProduct < ActiveRecord::Migration
|
533
698
|
def change
|
534
|
-
add_column :products, :flag, :
|
535
|
-
Product.all.each
|
699
|
+
add_column :products, :flag, :boolean
|
700
|
+
Product.all.each do |product|
|
701
|
+
product.update_attributes!(:flag => 'false')
|
702
|
+
end
|
536
703
|
end
|
537
704
|
end
|
538
705
|
</ruby>
|
@@ -545,7 +712,9 @@ class Product < ActiveRecord::Base
|
|
545
712
|
end
|
546
713
|
</ruby>
|
547
714
|
|
548
|
-
Alice adds a second migration which adds and initializes another column to the
|
715
|
+
Alice adds a second migration which adds and initializes another column to the
|
716
|
+
+products+ table and also adds a validation to the +Product+ model for the new
|
717
|
+
column.
|
549
718
|
|
550
719
|
<ruby>
|
551
720
|
# db/migrate/20100515121110_add_fuzz_to_product.rb
|
@@ -553,7 +722,9 @@ Alice adds a second migration which adds and initializes another column to the +
|
|
553
722
|
class AddFuzzToProduct < ActiveRecord::Migration
|
554
723
|
def change
|
555
724
|
add_column :products, :fuzz, :string
|
556
|
-
Product.all.each
|
725
|
+
Product.all.each do |product|
|
726
|
+
product.update_attributes! :fuzz => 'fuzzy'
|
727
|
+
end
|
557
728
|
end
|
558
729
|
end
|
559
730
|
</ruby>
|
@@ -570,10 +741,14 @@ Both migrations work for Alice.
|
|
570
741
|
|
571
742
|
Bob comes back from vacation and:
|
572
743
|
|
573
|
-
#
|
574
|
-
|
744
|
+
# Updates the source - which contains both migrations and the latests version of
|
745
|
+
the Product model.
|
746
|
+
# Runs outstanding migrations with +rake db:migrate+, which
|
747
|
+
includes the one that updates the +Product+ model.
|
575
748
|
|
576
|
-
The migration crashes because when the model attempts to save, it tries to
|
749
|
+
The migration crashes because when the model attempts to save, it tries to
|
750
|
+
validate the second added column, which is not in the database when the _first_
|
751
|
+
migration runs:
|
577
752
|
|
578
753
|
<plain>
|
579
754
|
rake aborted!
|
@@ -582,9 +757,12 @@ An error has occurred, this and all later migrations canceled:
|
|
582
757
|
undefined method `fuzz' for #<Product:0x000001049b14a0>
|
583
758
|
</plain>
|
584
759
|
|
585
|
-
A fix for this is to create a local model within the migration. This keeps rails
|
760
|
+
A fix for this is to create a local model within the migration. This keeps rails
|
761
|
+
from running the validations, so that the migrations run to completion.
|
586
762
|
|
587
|
-
When using a faux model, it's a good idea to call
|
763
|
+
When using a faux model, it's a good idea to call
|
764
|
+
+Product.reset_column_information+ to refresh the +ActiveRecord+ cache for the
|
765
|
+
+Product+ model prior to updating data in the database.
|
588
766
|
|
589
767
|
If Alice had done this instead, there would have been no problem:
|
590
768
|
|
@@ -596,9 +774,11 @@ class AddFlagToProduct < ActiveRecord::Migration
|
|
596
774
|
end
|
597
775
|
|
598
776
|
def change
|
599
|
-
add_column :products, :flag, :
|
777
|
+
add_column :products, :flag, :integer
|
600
778
|
Product.reset_column_information
|
601
|
-
Product.all.each
|
779
|
+
Product.all.each do |product|
|
780
|
+
product.update_attributes!(:flag => false)
|
781
|
+
end
|
602
782
|
end
|
603
783
|
end
|
604
784
|
</ruby>
|
@@ -609,32 +789,50 @@ end
|
|
609
789
|
class AddFuzzToProduct < ActiveRecord::Migration
|
610
790
|
class Product < ActiveRecord::Base
|
611
791
|
end
|
792
|
+
|
612
793
|
def change
|
613
794
|
add_column :products, :fuzz, :string
|
614
795
|
Product.reset_column_information
|
615
|
-
Product.all.each
|
796
|
+
Product.all.each do |product|
|
797
|
+
product.update_attributes!(:fuzz => 'fuzzy')
|
798
|
+
end
|
616
799
|
end
|
617
800
|
end
|
618
801
|
</ruby>
|
619
802
|
|
620
|
-
|
621
803
|
h3. Schema Dumping and You
|
622
804
|
|
623
805
|
h4. What are Schema Files for?
|
624
806
|
|
625
|
-
Migrations, mighty as they may be, are not the authoritative source for your
|
807
|
+
Migrations, mighty as they may be, are not the authoritative source for your
|
808
|
+
database schema. That role falls to either +db/schema.rb+ or an SQL file which
|
809
|
+
Active Record generates by examining the database. They are not designed to be
|
810
|
+
edited, they just represent the current state of the database.
|
626
811
|
|
627
|
-
There is no need (and it is error prone) to deploy a new instance of an app by
|
812
|
+
There is no need (and it is error prone) to deploy a new instance of an app by
|
813
|
+
replaying the entire migration history. It is much simpler and faster to just
|
814
|
+
load into the database a description of the current schema.
|
628
815
|
|
629
|
-
For example, this is how the test database is created: the current development
|
816
|
+
For example, this is how the test database is created: the current development
|
817
|
+
database is dumped (either to +db/schema.rb+ or +db/development.sql+) and then
|
818
|
+
loaded into the test database.
|
630
819
|
|
631
|
-
Schema files are also useful if you want a quick look at what attributes an
|
820
|
+
Schema files are also useful if you want a quick look at what attributes an
|
821
|
+
Active Record object has. This information is not in the model's code and is
|
822
|
+
frequently spread across several migrations, but the information is nicely
|
823
|
+
summed up in the schema file. The
|
824
|
+
"annotate_models":https://github.com/ctran/annotate_models gem automatically
|
825
|
+
adds and updates comments at the top of each model summarizing the schema if
|
826
|
+
you desire that functionality.
|
632
827
|
|
633
828
|
h4. Types of Schema Dumps
|
634
829
|
|
635
|
-
There are two ways to dump the schema. This is set in +config/application.rb+ by
|
830
|
+
There are two ways to dump the schema. This is set in +config/application.rb+ by
|
831
|
+
the +config.active_record.schema_format+ setting, which may be either +:sql+ or
|
832
|
+
+:ruby+.
|
636
833
|
|
637
|
-
If +:ruby+ is selected then the schema is stored in +db/schema.rb+. If you look
|
834
|
+
If +:ruby+ is selected then the schema is stored in +db/schema.rb+. If you look
|
835
|
+
at this file you'll find that it looks an awful lot like one very big migration:
|
638
836
|
|
639
837
|
<ruby>
|
640
838
|
ActiveRecord::Schema.define(:version => 20080906171750) do
|
@@ -646,36 +844,57 @@ ActiveRecord::Schema.define(:version => 20080906171750) do
|
|
646
844
|
|
647
845
|
create_table "products", :force => true do |t|
|
648
846
|
t.string "name"
|
649
|
-
t.text
|
847
|
+
t.text "description"
|
650
848
|
t.datetime "created_at"
|
651
849
|
t.datetime "updated_at"
|
652
|
-
t.string
|
850
|
+
t.string "part_number"
|
653
851
|
end
|
654
852
|
end
|
655
853
|
</ruby>
|
656
854
|
|
657
|
-
In many ways this is exactly what it is. This file is created by inspecting the
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
855
|
+
In many ways this is exactly what it is. This file is created by inspecting the
|
856
|
+
database and expressing its structure using +create_table+, +add_index+, and so
|
857
|
+
on. Because this is database-independent, it could be loaded into any database
|
858
|
+
that Active Record supports. This could be very useful if you were to distribute
|
859
|
+
an application that is able to run against multiple databases.
|
860
|
+
|
861
|
+
There is however a trade-off: +db/schema.rb+ cannot express database specific
|
862
|
+
items such as foreign key constraints, triggers, or stored procedures. While in
|
863
|
+
a migration you can execute custom SQL statements, the schema dumper cannot
|
864
|
+
reconstitute those statements from the database. If you are using features like
|
865
|
+
this, then you should set the schema format to +:sql+.
|
866
|
+
|
867
|
+
Instead of using Active Record's schema dumper, the database's structure will be
|
868
|
+
dumped using a tool specific to the database (via the +db:structure:dump+ Rake task)
|
869
|
+
into +db/structure.sql+. For example, for the PostgreSQL RDBMS, the
|
870
|
+
+pg_dump+ utility is used. For MySQL, this file will contain the output of +SHOW
|
871
|
+
CREATE TABLE+ for the various tables. Loading these schemas is simply a question
|
872
|
+
of executing the SQL statements they contain. By definition, this will create a
|
873
|
+
perfect copy of the database's structure. Using the +:sql+ schema format will,
|
874
|
+
however, prevent loading the schema into a RDBMS other than the one used to
|
875
|
+
create it.
|
664
876
|
|
665
877
|
h4. Schema Dumps and Source Control
|
666
878
|
|
667
|
-
Because schema dumps are the authoritative source for your database schema, it
|
879
|
+
Because schema dumps are the authoritative source for your database schema, it
|
880
|
+
is strongly recommended that you check them into source control.
|
668
881
|
|
669
882
|
h3. Active Record and Referential Integrity
|
670
883
|
|
671
|
-
The Active Record way claims that intelligence belongs in your models, not in
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
884
|
+
The Active Record way claims that intelligence belongs in your models, not in
|
885
|
+
the database. As such, features such as triggers or foreign key constraints,
|
886
|
+
which push some of that intelligence back into the database, are not heavily
|
887
|
+
used.
|
888
|
+
|
889
|
+
Validations such as +validates :foreign_key, :uniqueness => true+ are one way in
|
890
|
+
which models can enforce data integrity. The +:dependent+ option on associations
|
891
|
+
allows models to automatically destroy child objects when the parent is
|
892
|
+
destroyed. Like anything which operates at the application level, these cannot
|
893
|
+
guarantee referential integrity and so some people augment them with foreign key
|
894
|
+
constraints in the database.
|
895
|
+
|
896
|
+
Although Active Record does not provide any tools for working directly with such
|
897
|
+
features, the +execute+ method can be used to execute arbitrary SQL. You could
|
898
|
+
also use some plugin like "foreigner":https://github.com/matthuhiggins/foreigner
|
899
|
+
which add foreign key support to Active Record (including support for dumping
|
900
|
+
foreign keys in +db/schema.rb+).
|