WideFix tech post

Polish Rails migrations

Sometimes, it’s needed to re-run a new migration in a feature-branch back and forth several times due to code changes, a typo fixing, performance improvement, rebasing and etc. That can be done by using the most popular rake commands: rake db:rollback so many types as it’s needed to get to the migration should be changed (or even easier rake db:rollback STEP=3 where 3 is the number of steps back), change this migration and run rake db:migrate - that’s all, easy-peasy. Isn’t it? But, what if there is a typo or mistake in this migration again? What do you do? Repeat the process again? That issue might get too annoying. In this post I show you an alternative idea how to relieve the pain and start feeling more comfortable in writing migrations.


Just imagine the situation below. There is the list of migrations in your Rails app:

< > 20180317144803_migration1.rb
< > 20180317144804_migration2.rb
< > 20180317144814_migrationN.rb

These all migrations have been run locally. The migration 1 should be altered. Moreover, it’s clear there is no need to re-run them all migrations from 2 to N. Migrating all of them back to the first migration might turn into a pain, especially working on a big problem in a big team, that changes the migrations list too often. Just especially for that case, there is a special list of rake tasks kindly provided by Rails.


Long story short, to run the migration (it and only it!) back use this command:

rake db:migrate:down VERSION=20180317144803

Then make a necessary change in the migration. And run the migration forth:

rake db:migrate:up VERSION=20180317144803

Taking these rake tasks as the problem solution, pay attention that migrations can be run in any order in Rails. But sometimes, they might depend on each other. This happens more often at the beginning of a project development. So, to be on the safe side run all of them down and forth at least once like this:

rake db:rollback STEP=12
rake db:migrate

12 is the N here.

To boot

And for the dessert, check out this command that shows status for all migrations in a Rails project:

rake db:migrate:status

This is the output I got on a test project:

database: test-dev

 Status   Migration ID    Migration Name
   up     20180322190630  Remove special name
   up     20180326210602  Add default for users
  down    20180405124704  Add email
   up     20180406205508  Remove email

So, in this particular example when it’s executed rake db:migrate:up VERSION=20180405124704 the status turns into this state:

database: test-dev

 Status   Migration ID    Migration Name
   up     20180322190630  Remove special name
   up     20180326210602  Add default for users
   up     20180405124704  Add email
   up     20180406205508  Remove email

When rake db:migrate:down VERSION=20180405124704 to the previous state correspondingly.

It’s also can be useful the following command:

rake db:migrate:down VERSION=20180405124704

That combines the two actions (up and down) in one: firstly it tries to do down and then - up. More information about these tasks can be found in the Rails source code here.


A migration adjustment could be a huge pain. But thankfully Rails, this process is a pleasure to work with. There are may be provided many pieces of advice for this kind of job. But I would rather caution you that it’s not possible to have written an instruction for every case you have in your daily work. Just read the errors you have in the migrations and follow common sense. For example, when an error says there is no such table x that is being tried to be deleted, then maybe you are doing something wrong and have a mess in your DB. So maybe, the DB should be re-initiated with the new data. Or you can just comment this line in the migration for this run and uncomment it back when it’s done (this can be accepted in some circumstances when you are experimenting with a new migration you are working on).

Are you seeking assistance with Ruby on Rails development?

Read also