When is it acceptable to raise an ActiveRecord::IrreversibleMigration exception in the self.down method of a migration? When should you take the effort to actually implement the reverse of the migration?
7 Answers
If you are dealing with production-grade systems then yes, it is very bad. If it is your own pet project, then anything is allowed (if nothing else, it will be a learning experience :) though chances are that sooner rather than later, even in a pet project, you will find yourself having put a cross over a reverse migration only to have to undo that migration a few days later, be it via rake
or manually.)
In a production scenario, you should always make the effort to write and test a reversible migration in the eventuality that you go through it in production, then discover a bug which forces you to roll back (code and schema) to some previous revision (pending some non-trivial fix -- and an otherwise unusable production system.)
Reverse migrations range from mostly trivial (removing columns or tables that were added during migration, and/or changing column types, etc.) to somewhat more involved (execute
of JOIN
ed INSERT
s or UPDATE
s), but nothing is so complex as to justify "sweeping it under the rug". If nothing else, forcing yourself to think of ways to achieve reverse migrations can give you new insight into the very problem that your forward migration is fixing.
You might occasionally run into a situation where a forward migration removes a feature, resulting in data being discarded from the database. For obvious reasons, the reverse migration cannot resuscitate discarded data. Although one could, in such cases, recommend having the forward migration automatically save the data or keep it around in the eventuality of rollback as an alternative to outright failure (save to yml
, copy/move to a special table, etc.), you don't have to, as the time required to test such an automated procedure could exceed the time required to restore the data manually (should the need arise.) But even in such cases, instead of just failing, you can always make the reverse migration conditionally and temporarily fail pending some user action (i.e. test for the existence of some required table that has to be restored manually; if missing, output "I have failed because I cannot recreate table XYZ
from nothingness; manually restore table XYZ
from backup then run me again, and I will not fail you!")

- 65,483
- 18
- 129
- 130
-
Once you have dozens or hundreds of migrations, it's worthwhile to throw an exception in the up as well, to the effect of "THIS IS IRREVERSIBLE. ARE YOU SURE?" – Sarah Mei Mar 07 '09 at 17:05
-
You can use [OffScale DataGrove](http://off-scale.com) to save the complete state of the DB before running a migration. If you ever need to revert a migration, you can do it even in the case where your migration actually discards data. You can also use it to test migrations. – Taichman Dec 01 '11 at 13:41
If you are destroying data, you can make a backup of it first. e.g.
def self.up
# create a backup table before destroying data
execute %Q[create table backup_users select * from users]
remove_column :users, :timezone
end
def self.down
add_column :users, :timezone, :string
execute %Q[update users U left join backup_users B on (B.id=U.id) set U.timezone = B.timezone]
execute %Q[drop table backup_users]
end

- 13,211
- 19
- 77
- 138

- 291
- 3
- 2
In a production scenario, you should always make the effort to write and test a reversible migration in the eventuality that you go through it in production, then discover a bug which forces you to roll back (code and schema) to some previous revision (pending some non-trivial fix -- and an otherwise unusable production system.)
Having a reversible migration is fine for development and staging, but assuming well tested code it should be extremely rare that you would ever want to migrate down in production. I build into my migrations an automatic IrreversibleMigration in production mode. If I really needed to reverse a change, I could use another "up" migration or remove the exception. That seems sketchy though. Any bug that would cause a scenario this dire is a sign that the QA process is seriously screwed up.

- 17,702
- 4
- 51
- 54
-
7Or that the company is too small to have a good QA process, or the managers don't support it. – Tilendor Mar 08 '09 at 17:47
-
There is one thing we typically accept as a difference between production and staging: the content of the databases. It follows that the most likely thing to be uncatchable by QA would be a migration hitting an overlooked case. It's also one of the most potentially severe things that could go wrong. Seems reasonable to be cautious. – Adamantish Mar 26 '19 at 16:18
Feeling like you need an irreversible migration is probably a sign you've got bigger problems looming. Maybe some specifics would help?
As for your second question: I always take the 'effort' to write the reverse of migrations. Of course, I don't actually write the .down
, TextMate inserts it automatically when creating the .up
.

- 30,053
- 5
- 59
- 54
Reversible Data Migration makes it easy to create reversable data migrations using yaml files.
class RemoveStateFromProduct < ActiveRecord::Migration
def self.up
backup_data = []
Product.all.each do |product|
backup_data << {:id => product.id, :state => product.state}
end
backup backup_data
remove_column :products, :state
end
def self.down
add_column :products, :state, :string
restore Product
end
end

- 1,969
- 3
- 21
- 24
IIRC, you'll have the IrreversibleMigration when changing a datatype in the migration.

- 12,478
- 8
- 25
- 25
I think another situation when it's ok is when you have a consolidated migration. In that case a "down" doesn't really make sense, as it would drop all the tables (except tables added after the consolidation). That's probably not what you'd want.

- 3,062
- 2
- 15
- 9