views:

6684

answers:

5

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?

Thanks, Rollo

+2  A: 

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 sqllite, it might be a bug specific to such an environement.

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 ...

Jean
A: 

This is not the expected behaviour. I was going to suggest reporting this as a bug on lighthouse, but I see you've already done so! If you provide some more information (including OS/database/ruby version) I will take a look at it.

tomafro
A: 

I will close the lighthouse bug, and point to here

tomafro
+1  A: 

I respectfully disagree Tom! this is a bug !! V3.5.0f is not a valid version for rake migrations. Rake should not use it to migrate:down just because ruby chose to consider that "V3.5.0f".to_i is 0 ...

Rake should loudly complain that VERSION is not valid so that users know what is up (between you and me, checking that the version is a YYYYMMDD formated timestamp by converting to integer is a bit light)

[Damn IE6 that won't allow me to comment ! and no I can't change browser thanks corporate]

Jean
+1  A: 

Jean,

Thanks a lot for your investigation. You're right, and actually I think you've uncovered a more severe bug, of species 'design bug'.

What's happening is that rake will grab whatever value you pass to the command line and store them as environment variables. The rake tasks that will eventually get called will just pull this values from the environment variable. When db:migrate queries ENV["VERSION"], it actually requests the version parameter which you set calling rake. When you call rake db:migrate, you don't pass any version.

But we do have an environment variable called VERSION that has been set for other purposes by some other program (I don't which one yet). And the guys behind rake (or behind database.rake) haven't figured this would happen. That's a design bug. At least, they could have used more specific variable names like "RAKE_VERSION" or "RAKE_PARAM_VERSION" instead of just "VERSION".

Tom, I will definitely not close but edit my bug report on lighthouse to reflect these new findings.

And thanks again Jean for your help. I've posted this bug on lighthouse like 5 days agao and still got no answer!

Rollo

Rollo Tomazzi