Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails: Is it bad to have an irreversible migration?

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?

like image 289
readonly Avatar asked Mar 07 '09 03:03

readonly


People also ask

What is irreversible migration?

The migration that cannot be undone: Irreversible Migration.

What is reversible migration?

Introduced in Rails 4.0, reversible makes it possible to tell a migration using change (instead of up and down ) how to reverse migrations that Active Record doesn't know how to reverse by default, so that you can specify code to be executed whether migrating forward or rolling back, even inside a migration implemented ...

How do I rollback a migration in Rails?

You must rollback the migration (for example with bin/rails db:rollback ), edit your migration, and then run bin/rails db:migrate to run the corrected version.

How does Rails migration work?

A Rails migration is a tool for changing an application's database schema. Instead of managing SQL scripts, you define database changes in a domain-specific language (DSL). The code is database-independent, so you can easily move your app to a new platform.


2 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 JOINed INSERTs or UPDATEs), 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!")

like image 92
vladr Avatar answered Sep 20 '22 16:09

vladr


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 
like image 37
Mark Lanett Avatar answered Sep 18 '22 16:09

Mark Lanett