2

I am having some problems with rake db:rollback. Here's the setup:

One week ago I pulled some changes from the repository, which included a new migration. I ran rake db:migrate and all was well with the world. Fast-forward 7 days (and multiple commits and pushes), and I started working on a new feature. I created a new feature branch and then created a new migration. I ran that migration, wrote some codes, then realized I had made a small error in the migration that I had just created. I thought I could just run rake db:rollback, make a few changes to that one migration, and then rake db:migrate again.

But here's the rub. When I ran rake db:rollback it rolled back two migrations instead of just one. Running rake db:migrate then migrates both of those migrations. I can go back and forth all day long, but every time it always rolls back 2 migrations.

I did some searching around here on stackoverflow and found this question that is specifically referencing the STEP parameter that can be added to migrate and rollback, but going through everything in that question has not helped me. At first nothing was returned when I ran echo $STEP, so I specifically set it with export STEP=1, but that didn't help: rake db:rollback still rolls back 2 steps every time. And, even when I run rake db:rollback STEP=1 it still rolls back 2 steps.

Also, I checked the version number in the schema, and just after running rake db:migrate the version is consistent with the newest migration that I just created. After running rake db:rollback and it going back 2 steps, the version number is consistent with the 2nd most recent migration.

I want to solve this problem for 2 reasons:

  1. I need to rollback only one migration so I can commit my changes and then switch back to the development branch and not pollute the developement schema.
  2. I want to fully understand how rake db:rollback works. Maybe there is a way to hack this out and get things going, but I want to understand this at a deeper level.

Is there some sort of app config that determines this? Have some wires gotten crossed and I need to manually reset something? Thanks for your help!

UPDATE

As per some comments and responses:

I explicitly set export STEP=1 in my .bash_profile and that hasn't made a difference and it still rolls back 2 steps.

I was aware of migrating to a specific version, and yes, that is a way to get to specific place for me. I can rollback the 2 steps that it is forcing me and then migrate forward 1 step by specifying the version. It works, but it's not how this should work and I really want to get to the bottom of all this.

The output of rake db:migrate:status always returns this error:

rake aborted!
ArgumentError: invalid value for Integer(): ""
/Users/eliduke/.rvm/gems/ruby-2.1.0/gems/activerecord-4.0.5/lib/active_record/railties/databases.rake:98:in `%'
/Users/eliduke/.rvm/gems/ruby-2.1.0/gems/activerecord-4.0.5/lib/active_record/railties/databases.rake:98:in `block (4 levels) in <top (required)>'
/Users/eliduke/.rvm/gems/ruby-2.1.0/gems/activerecord-4.0.5/lib/active_record/railties/databases.rake:98:in `map!'
/Users/eliduke/.rvm/gems/ruby-2.1.0/gems/activerecord-4.0.5/lib/active_record/railties/databases.rake:98:in `block (3 levels) in <top (required)>'
/Users/eliduke/.rvm/gems/ruby-2.1.0/bin/ruby_executable_hooks:15:in `eval'
/Users/eliduke/.rvm/gems/ruby-2.1.0/bin/ruby_executable_hooks:15:in `<main>'
Tasks: TOP => db:migrate:status

And the output of rake db:version might be acting strange. If I have just recently migrated all the way forward, it is 20150309194758, which corresponds to my most recent migration. If I have just rolled back (the 2 steps it is forcing me), the version is 20150203171351, which corresponds to the migration that is 3 steps back. Is that normal? Shouldn't it be 20150303192838, which is 2 steps back?

Also, I now see a peculiarity in the output for rake db:rollback. It first shows the rolling back of the first migration like normal (1 step) and then it looks like maybe the Apartment gem is chiming in and rolling back the next migration (2 step).

== 20150309194758 CreateFeeds: reverting ======================================
-- drop_table(:feeds, {:id=>false})
   -> 0.0291s
== 20150309194758 CreateFeeds: reverted (0.0293s) =============================

Rolling back development tenant
== 20150303192838 AddDisplayRankToEventPrizes: reverting ======================
-- remove_column(:event_prizes, :display_rank, :integer, {:index=>true, :after=>:winner_user_id})
   -> 0.5963s
== 20150303192838 AddDisplayRankToEventPrizes: reverted (0.5964s) =============

See that Rolling back development tenant line? Could the apartment gem be causing the 2nd step rollback?

Eli Duke
  • 454
  • 1
  • 3
  • 14

2 Answers2

2

If you have a specific migration and don't want to touch any other migrations, you can run rake db:migrate:redo VERSION="XXXXXXXXXXX" to re-run just that specific migration.

The VERSION ID is the longer number that prefixes all of your migrations, which just connotes the date/time at which it was created. So if I had a migration file named: 20150114194155_add_foo_to_bar my command would be something like this:

rake db:migrate:redo VERSION="20150114194155"

If you truly need to leave a migration in its "down" state, it'll be a little more work. First, make sure your target migration has a down action. Then, simply run:

rake db:migrate:down VERSION="20150114194155"

This will run the "down" action on that single migration.

Here's the Rails documentation to learn more.

Collin Graves
  • 2,207
  • 15
  • 11
1

In the rail codebase you can find: line 125

desc 'Rolls the schema back to the previous version (specify steps w/ STEP=n).'
task :rollback => [:environment, :load_config] do
  step = ENV['STEP'] ? ENV['STEP'].to_i : 1
  ActiveRecord::Migrator.rollback(ActiveRecord::Migrator.migrations_paths, step)
  db_namespace['_dump'].invoke
end

So if the environment variable has to be set somewhere. Non the less, it's a good practice to always specify the number of steps:

rake db:rollback STEP=1

tiagotex
  • 56
  • 5