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.