aboutsummaryrefslogtreecommitdiffstats
path: root/guides/source
diff options
context:
space:
mode:
authorMarc-Andre Lafortune <github@marc-andre.ca>2012-12-19 14:46:16 -0500
committerMarc-Andre Lafortune <github@marc-andre.ca>2012-12-21 13:56:16 -0500
commita81845f26864d076970e706863c766aead432672 (patch)
treec5bd5f97be26a533877e043868e0995f30fba1b9 /guides/source
parent06c7ba881d008be82d62656f297d6a3c09a889c5 (diff)
downloadrails-a81845f26864d076970e706863c766aead432672.tar.gz
rails-a81845f26864d076970e706863c766aead432672.tar.bz2
rails-a81845f26864d076970e706863c766aead432672.zip
Update Migration and 4.0 Release Guides, Changelogs [#8267]
Diffstat (limited to 'guides/source')
-rw-r--r--guides/source/4_0_release_notes.md13
-rw-r--r--guides/source/migrations.md225
2 files changed, 202 insertions, 36 deletions
diff --git a/guides/source/4_0_release_notes.md b/guides/source/4_0_release_notes.md
index dd57787111..55ac4bca87 100644
--- a/guides/source/4_0_release_notes.md
+++ b/guides/source/4_0_release_notes.md
@@ -165,6 +165,19 @@ Please refer to the [Changelog](https://github.com/rails/rails/blob/master/railt
### Notable changes
+* Improve ways to write `change` migrations, making the old `up` & `down` methods no longer necessary.
+
+ * The methods `drop_table` and `remove_column` are now reversible, as long as the necessary information is given.
+ The method `remove_column` used to accept multiple column names; instead use `remove_columns` (which is not revertible).
+ The method `change_table` is also reversible, as long as its block doesn't call `remove`, `change` or `change_default`
+
+ * New method `reversible` makes it possible to specify code to be run when migrating up or down.
+ See the [Guide on Migration](https://github.com/rails/rails/blob/master/guides/source/migrations.md#using-the-reversible-method)
+
+ * New method `revert` will revert a whole migration or the given block.
+ If migrating down, the given migration / block is run normally.
+ See the [Guide on Migration](https://github.com/rails/rails/blob/master/guides/source/migrations.md#reverting-previous-migrations)
+
* Adds some metadata columns to `schema_migrations` table.
* `migrated_at`
diff --git a/guides/source/migrations.md b/guides/source/migrations.md
index 9840e7694f..62b70b5571 100644
--- a/guides/source/migrations.md
+++ b/guides/source/migrations.md
@@ -56,25 +56,40 @@ Before this migration is run, there will be no table. After, the table will
exist. Active Record knows how to reverse this migration as well: if we roll
this migration back, it will remove the table.
-On databases that support transactions with statements that change the schema ,
+On databases that support transactions with statements that change the schema,
migrations are wrapped in a transaction. If the database does not support this
then when a migration fails the parts of it that succeeded will not be rolled
back. You will have to rollback the changes that were made by hand.
If you wish for a migration to do something that Active Record doesn't know how
-to reverse, you can use `up` and `down` instead of `change`:
+to reverse, you can use `reversible`:
```ruby
class ChangeProductsPrice < ActiveRecord::Migration
+ def change
+ reversible do |dir|
+ change_table :products do |t|
+ dir.up { t.change :price, :string }
+ dir.down { t.change :price, :integer }
+ end
+ end
+ end
+end
+```
+
+Alternatively, you can use `up` and `down` instead of `change`:
+
+``ruby
+class ChangeProductsPrice < ActiveRecord::Migration
def up
change_table :products do |t|
- t.string :price, null: false
+ t.change :price, :string
end
end
-
+
def down
change_table :products do |t|
- t.integer :price, null: false
+ t.change :price, :integer
end
end
end
@@ -93,7 +108,7 @@ of the migration. The name of the migration class (CamelCased version)
should match the latter part of the file name. For example
`20080906120000_create_products.rb` should define class `CreateProducts` and
`20080906120001_add_details_to_products.rb` should define
-`AddDetailsToProducts`.
+`AddDetailsToProducts`.
Of course, calculating timestamps is no fun, so Active Record provides a
generator to handle making it for you:
@@ -139,12 +154,8 @@ generates
```ruby
class RemovePartNumberFromProducts < ActiveRecord::Migration
- def up
- remove_column :products, :part_number
- end
-
- def down
- add_column :products, :part_number, :string
+ def change
+ remove_column :products, :part_number, :string
end
end
```
@@ -170,10 +181,6 @@ As always, what has been generated for you is just a starting point. You can add
or remove from it as you see fit by editing the
`db/migrate/YYYYMMDDHHMMSS_add_details_to_products.rb` file.
-NOTE: The generated migration file for destructive migrations will still be
-old-style using the `up` and `down` methods. This is because Rails needs to
-know the original data types defined when you made the original changes.
-
Also, the generator accepts column type as `references`(also available as
`belongs_to`). For instance
@@ -346,7 +353,7 @@ Products.connection.execute('UPDATE `products` SET `price`=`free` WHERE 1')
For more details and examples of individual methods, check the API documentation.
In particular the documentation for
[`ActiveRecord::ConnectionAdapters::SchemaStatements`](http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html)
-(which provides the methods available in the `up` and `down` methods),
+(which provides the methods available in the `change`, `up` and `down` methods),
[`ActiveRecord::ConnectionAdapters::TableDefinition`](http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/TableDefinition.html)
(which provides the methods available on the object yielded by `create_table`)
and
@@ -362,25 +369,82 @@ definitions:
* `add_column`
* `add_index`
+* `add_reference`
* `add_timestamps`
* `create_table`
+* `create_join_table`
+* `drop_table` (must supply a block)
+* `drop_join_table` (must supply a block)
* `remove_timestamps`
* `rename_column`
* `rename_index`
+* `remove_reference`
* `rename_table`
-If you're going to need to use any other methods, you'll have to write the
-`up` and `down` methods instead of using the `change` method.
+`change_table` is also reversible, as long as the block does not call `change`,
+`change_default` or `remove`.
+
+If you're going to need to use any other methods, you should use `reversible`
+or write the `up` and `down` methods instead of using the `change` method.
+
+### Using `reversible`
+
+Complex migrations may require processing that Active Record doesn't know how
+to reverse. You can use `reversible` to specify what to do when running a
+migration what else to do when reverting it. For example,
+
+```ruby
+class ExampleMigration < ActiveRecord::Migration
+ def change
+ create_table :products do |t|
+ t.references :category
+ end
+
+ reversible do |dir|
+ dir.up do
+ #add a foreign key
+ execute <<-SQL
+ ALTER TABLE products
+ ADD CONSTRAINT fk_products_categories
+ FOREIGN KEY (category_id)
+ REFERENCES categories(id)
+ SQL
+ end
+ dir.down do
+ execute <<-SQL
+ ALTER TABLE products
+ DROP FOREIGN KEY fk_products_categories
+ SQL
+ end
+ end
+
+ add_column :users, :home_page_url, :string
+ rename_column :users, :email, :email_address
+ end
+```
+
+Using `reversible` will insure that the instructions are executed in the
+right order too. If the previous example migration is reverted,
+the `down` block will be run after the `home_page_url` column is removed and
+right before the table `products` is dropped.
+
+Sometimes your migration will do something which is just plain irreversible; for
+example, it might destroy some data. In such cases, you can raise
+`ActiveRecord::IrreversibleMigration` in your `down` block. If someone tries
+to revert your migration, an error message will be displayed saying that it
+can't be done.
### Using the `up`/`down` Methods
+You can also use the old style of migration using `up` and `down` methods
+instead of the `change` method.
The `up` method should describe the transformation you'd like to make to your
schema, and the `down` method of your migration should revert the
transformations done by the `up` method. In other words, the database schema
should be unchanged if you do an `up` followed by a `down`. For example, if you
create a table in the `up` method, you should drop it in the `down` method. It
is wise to reverse the transformations in precisely the reverse order they were
-made in the `up` method. For example,
+made in the `up` method. The example in the `reversible` section is equivalent to:
```ruby
class ExampleMigration < ActiveRecord::Migration
@@ -415,19 +479,92 @@ class ExampleMigration < ActiveRecord::Migration
end
```
-Sometimes your migration will do something which is just plain irreversible; for
-example, it might destroy some data. In such cases, you can raise
+If your migration is irreversible, you should raise
`ActiveRecord::IrreversibleMigration` from your `down` method. If someone tries
to revert your migration, an error message will be displayed saying that it
can't be done.
+### Reverting Previous Migrations
+
+You can use Active Record's ability to rollback migrations using the `revert` method:
+
+```ruby
+require_relative '2012121212_example_migration'
+
+class FixupExampleMigration < ActiveRecord::Migration
+ def change
+ revert ExampleMigration
+
+ create_table(:apples) do |t|
+ t.string :variety
+ end
+ end
+end
+```
+
+The `revert` method also accepts a block of instructions to reverse.
+This could be useful to revert selected parts of previous migrations.
+For example, let's imagine that `ExampleMigration` is committed and it
+is later decided it would be best to serialize the product list instead.
+One could write:
+
+```ruby
+class SerializeProductListMigration < ActiveRecord::Migration
+ def change
+ add_column :categories, :product_list
+
+ reversible do |dir|
+ dir.up do
+ # transfer data from Products to Category#product_list
+ end
+ dir.down do
+ # create Products from Category#product_list
+ end
+ end
+
+ revert do
+ # copy-pasted code from ExampleMigration
+ create_table :products do |t|
+ t.references :category
+ end
+
+ reversible do |dir|
+ dir.up do
+ #add a foreign key
+ execute <<-SQL
+ ALTER TABLE products
+ ADD CONSTRAINT fk_products_categories
+ FOREIGN KEY (category_id)
+ REFERENCES categories(id)
+ SQL
+ end
+ dir.down do
+ execute <<-SQL
+ ALTER TABLE products
+ DROP FOREIGN KEY fk_products_categories
+ SQL
+ end
+ end
+
+ # The rest of the migration was ok
+ end
+ end
+end
+```
+
+The same migration could also have been written without using `revert`
+but this would have involved a few more steps: reversing the order
+of `create_table` and `reversible`, replacing `create_table`
+by `drop_table`, and finally replacing `up` by `down` and vice-versa.
+This is all taken care of by `revert`.
+
Running Migrations
------------------
Rails provides a set of Rake tasks to run certain sets of migrations.
The very first migration related Rake task you will use will probably be
-`rake db:migrate`. In its most basic form it just runs the `up` or `change`
+`rake db:migrate`. In its most basic form it just runs the `change` or `up`
method for all the migrations that have not yet been run. If there are
no such migrations, it exits. It will run these migrations in order based
on the date of the migration.
@@ -436,7 +573,7 @@ Note that running the `db:migrate` also invokes the `db:schema:dump` task, which
will update your `db/schema.rb` file to match the structure of your database.
If you specify a target version, Active Record will run the required migrations
-(up, down or change) until it has reached the specified version. The version
+(change, up, down) until it has reached the specified version. The version
is the numerical prefix on the migration's filename. For example, to migrate
to version 20080906120000 run
@@ -445,7 +582,8 @@ $ rake db:migrate VERSION=20080906120000
```
If version 20080906120000 is greater than the current version (i.e., it is
-migrating upwards), this will run the `up` method on all migrations up to and
+migrating upwards), this will run the `change` (or `up`) method
+on all migrations up to and
including 20080906120000, and will not execute any later migrations. If
migrating downwards, this will run the `down` method on all the migrations
down to, but not including, 20080906120000.
@@ -460,14 +598,15 @@ number associated with the previous migration you can run
$ rake db:rollback
```
-This will run the `down` method from the latest migration. If you need to undo
+This will rollback the latest migration, either by reverting the `change`
+method or by running the `down` method. If you need to undo
several migrations you can provide a `STEP` parameter:
```bash
$ rake db:rollback STEP=3
```
-will run the `down` method from the last 3 migrations.
+will revert the last 3 migrations.
The `db:migrate:redo` task is a shortcut for doing a rollback and then migrating
back up again. As with the `db:rollback` task, you can use the `STEP` parameter
@@ -495,14 +634,15 @@ contents of the current schema.rb file. If a migration can't be rolled back,
If you need to run a specific migration up or down, the `db:migrate:up` and
`db:migrate:down` tasks will do that. Just specify the appropriate version and
-the corresponding migration will have its `up` or `down` method invoked, for
-example,
+the corresponding migration will have its `change`, `up` or `down` method
+invoked, for example,
```bash
$ rake db:migrate:up VERSION=20080906120000
```
-will run the `up` method from the 20080906120000 migration. This task will
+will run the 20080906120000 migration by running the `change` method (or the
+`up` method). This task will
first check whether the migration is already performed and will do nothing if
Active Record believes that it has already been run.
@@ -596,6 +736,10 @@ you require. Editing a freshly generated migration that has not yet been
committed to source control (or, more generally, which has not been propagated
beyond your development machine) is relatively harmless.
+The `revert` method can be helpful when writing a new migration to undo
+previous migrations in whole or in part
+(see [Reverting Previous Migrations](#reverting-previous-migrations) above).
+
Using Models in Your Migrations
-------------------------------
@@ -622,6 +766,9 @@ column.
class AddFlagToProduct < ActiveRecord::Migration
def change
add_column :products, :flag, :boolean
+ reversible do |dir|
+ dir.up { Product.update_all flag: false }
+ end
Product.update_all flag: false
end
end
@@ -645,7 +792,9 @@ column.
class AddFuzzToProduct < ActiveRecord::Migration
def change
add_column :products, :fuzz, :string
- Product.update_all fuzz: 'fuzzy'
+ reversible do |dir|
+ dir.up { Product.update_all fuzz: 'fuzzy' }
+ end
end
end
```
@@ -697,7 +846,9 @@ class AddFlagToProduct < ActiveRecord::Migration
def change
add_column :products, :flag, :boolean
Product.reset_column_information
- Product.update_all flag: false
+ reversible do |dir|
+ dir.up { Product.update_all flag: false }
+ end
end
end
```
@@ -712,7 +863,9 @@ class AddFuzzToProduct < ActiveRecord::Migration
def change
add_column :products, :fuzz, :string
Product.reset_column_information
- Product.update_all fuzz: 'fuzzy'
+ reversible do |dir|
+ dir.up { Product.update_all fuzz: 'fuzzy' }
+ end
end
end
```
@@ -810,9 +963,9 @@ Rake task) into `db/structure.sql`. For example, for PostgreSQL, the `pg_dump`
utility is used. For MySQL, this file will contain the output of `SHOW CREATE
TABLE` for the various tables.
-Loading these schemas is simply a question of executing the SQL statements they
-contain. By definition, this will create a perfect copy of the database's
-structure. Using the `:sql` schema format will, however, prevent loading the
+Loading these schemas is simply a question of executing the SQL statements they
+contain. By definition, this will create a perfect copy of the database's
+structure. Using the `:sql` schema format will, however, prevent loading the
schema into a RDBMS other than the one used to create it.
### Schema Dumps and Source Control