Ruby-on-rails – rake db:migrate doesn’t detect new migration

activerecordmigrationruby-on-rails

Experienced with Rails / ActiveRecord 2.1.1

  • You create a first version with (for example) ruby script\generate scaffold product title:string description:text image_url:string
  • This create (for example) a migration file called 20080910122415_create_products.rb
  • You apply the migration with rake db:migrate
  • Now, you add a field to the product table with ruby script\generate migration add_price_to_product price:decimal
  • This create a migration file called 20080910125745_add_price_to_product.rb
  • If you try to run rake db:migrate, it will actually revert the first migration, not apply the next one! So your product table will get destroyed!
  • But if you ran rake alone, it would have told you that one migration was pending

Pls note that applying rake db:migrate (once the table has been destroyed) will apply all migrations in order.

The only workaround I found is to specify the version of the new migration as in:

rake db:migrate version=20080910125745

So I'm wondering: is this an expected new behavior?

Best Solution

You should be able to use

rake db:migrate:up 

to force it to go forward, but then you risk missing interleaved migrations from other people on your team

if you run

rake db:migrate 

twice, it will reapply all your migrations.

I encounter the same behavior on windows with SQLite, it might be a bug specific to such an environment.

Edit -- I found why. In the railstie database.rake task you have the following code :

desc "Migrate the database through scripts in db/migrate. Target specific version with VERSION=x. Turn off output with VERBOSE=false."
task :migrate => :environment do
  ActiveRecord::Migration.verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] == "true" : true
  ActiveRecord::Migrator.migrate("db/migrate/", ENV["VERSION"] ? ENV["VERSION"].to_i : nil)
  Rake::Task["db:schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby
end

Then in my environment variables I have

echo %Version% #=> V3.5.0f

in Ruby

ENV["VERSION"] # => V3.5.0f
ENV["VERSION"].to_i #=>0 not nil !

thus the rake task calls

ActiveRecord::Migrator.migrate("db/migrate/", 0)

and in ActiveRecord::Migrator we have :

class Migrator#:nodoc:
  class << self
    def migrate(migrations_path, target_version = nil)
      case
        when target_version.nil?              then up(migrations_path, target_version)
        when current_version > target_version then down(migrations_path, target_version)
        else                                       up(migrations_path, target_version)
      end
    end

Yes, rake db:migrate VERSION=0 is the long version for rake db:migrate:down

Edit - I would go update the lighthouse bug but I the super company proxy forbids that I connect there

In the meantime you may try to unset Version before you call migrate ...