Posted over 7 years ago. Visible to the public. Repeats.

How to combine "change", "up", and "down" in a Rails migration

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 Archive :

Copy
class MyMigration < ActiveRecord::Migration def change rename_table :old_table, :new_table add_column :new_table, :foo # ... reversible do |change| change.up do update "UPDATE new_table SET foo = something_really_complex" end change.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):

Copy
class MyMigration < ActiveRecord::Migration def change rename_table :old_table, :new_table add_column :new_table, :foo # ... up_only { "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.

Copy
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.

Does your version of Ruby on Rails still receive security updates?
Rails LTS provides security patches for unsupported versions of Ruby on Rails (2.3, 3.2, 4.2 and 5.2).

Owner of this card:

Avatar
Arne Hartherz
Last edit:
6 months ago
by Arne Hartherz
Keywords:
migrate
About this deck:
We are makandra and do test-driven, agile Ruby on Rails software development.
License for source code
Posted by Arne Hartherz to makandra dev
This website uses short-lived cookies to improve usability.
Accept or learn more