Rails migrations allow you to use a change
method whose calls are automatically inverted for the down path. However, if you need to some path-specific logic (like SQL UPDATE
statements) you can not define up
and down
methods at the same time.
If you were to define define all 3 of them, Rails would only run change
and ignore up
and down
. However, Rails 4+ features a helper method called
reversible
Show archive.org snapshot
:
class MyMigration < ActiveRecord::Migration
def change
rename_table :old_table, :new_table
add_column :new_table, :foo
# ...
reversible do |direction|
direction.up do
update "UPDATE new_table SET foo = something_really_complex"
end
direction.down do
update "UPDATE new_table SET foo = what_it_was_before"
end
end
end
end
Note that the "down" path is like running the change
block from bottom upwards. This is relevant when writing SQL statements: When migrating down, the rename_table
statement will be run after the reversible
block. While this makes sense, it may feel odd that the SQL statement says "UPDATE new_table
".
If your migration becomes too complex, you could put your logic into multiple reversible
blocks (so they contain only one of up
/down
).
When you only need to do something when migrating "up", you can use up_only
(available since Rails 5.2):
class MyMigration < ActiveRecord::Migration
def change
rename_table :old_table, :new_table
add_column :new_table, :foo
# ...
up_only { update "UPDATE new_table SET foo = something_really_complex" }
end
end
While there is no down_only
, you can use reverting?
and avoid the reversible
boilerplate. It might be less intuitive since if reverting?
puts the "down" path first.
class MyMigration < ActiveRecord::Migration
def change
rename_table :old_table, :new_table
add_column :new_table, :foo
# ...
if reverting?
update "UPDATE new_table SET foo = what_it_was_before"
else
update "UPDATE new_table SET foo = something_really_complex"
end
end
end
A word of advice: Depending on your migration, you might be better off just defining 2 separate up
and down
methods instead of using change
.