I just discovered something relatively simply that eluded me since the very start of my career in Rails. You’re working on several branches, migrating between them sometimes having to run a db migration. Sometimes you or a colleague writes a non-forward compatible migration, making the code on master (for example) unable to be run against a later migration that happened in a different branch.

No problem, rake db:rollback to the rescue! Let’s assume for the sake of this post you know how to

bundle exec rake db:migrate

(This runs all migrations that have been run in the order they are timestamped.)

Let’s also assume you know how to

bundle exec rake db:rollback

This rolls back the last migration – sort of. And it’s the “sort of” where things get tricky when switching branches. The question is: Does it rollback the last migration that is in your project code (in the db/migrate/ folder), or does it rollback the last migration that’s recorded by timestamp record in your schema_migrations table. (The answer is the latter.)

Let’s say you create a branch, create & run a migration, then switch to another branch. On another branch, you already had a migration that already got run, but doesn’t work with this new branch. So you run

bundle exec rake db:rollback

You sit and watch it do nothing. No error message, no notice telling you a migration was rolled back. WTF! you say, you look in your db/migrate/ folder and examine the last file in there. You bang you fists against the wall wondering why nothing happened.

And then you realize you switched branches, and here’s the catch: db:rollback actually doesn’t look at the last migration from your code, it looks at the last migration in the schema_migrations table. When it doesn’t find that migration, it does nothing. No error or notification, it simply exits.

You can gain a little insight into this by using the rake db:migrate:status task, which lists for you what’s been run.

Normally, you will see something like so:

  up   20131217223201 Create bulbs
  up   20131219222719 Index bulbs
  up   20131223185138 Add index to Users updated at
  up   20131230143845 Add slug to groupings
  up   20140102174204 Drop train_tracks
  up   20140108101528 Add fields to clouds table
  up   20140108193156 Create references table

This tells you that these migrations were run successfully. If you’ve switched branches however and the last migration in your schema table is no longer in your code (because you switched branches), rake can’t know about its existence – except that it does know about its existence because of the entry in the schema_migrations table. So when you run status, it shows you the timestamp with a big “NO FILE” sign next to it.

  up   20131217223201 Create bulbs
  up   20131219222719 Index bulbs
  up   20131223185138 Add index to Users updated at
  up   20131230143845 Add slug to groupings
  up   20140102174204 Drop train_tracks
  up   20140108101528 Add fields to clouds table
  up   20140108193156 ********** NO FILE **********

You can of course do two things to remedy this, 1) keep track of which branch you’re on and which migration you want to rollback, or 2) use the rake db:migrate:down VERSION=… syntax instead. If you do that and pass it a migration that doesn’t exist in your current branch, the task gives you a real error message like so:

No migration with version number 20140117171003

So, probably for this reason it’s a good habit to use db:migrate:down instead of db:rollback.

By Jason

Leave a Reply

Your email address will not be published. Required fields are marked *