This project is archived and is in readonly mode.

#1021 ✓ duplicate
Rollo Tomazzi

rake db:migrate doesn't detect new migration

Reported by Rollo Tomazzi | September 11th, 2008 @ 10:30 AM | in 2.x

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

Comments and changes to this ticket

  • Tom Ward

    Tom Ward September 16th, 2008 @ 10:51 AM

    • Tag changed from activerecord, migration to activerecord, migration

    Rollo,

    Could you tell me what OS/Database/Version of Ruby you are using? It will help in trying to recreate the issue.

    Tom

  • Tom Ward

    Tom Ward September 16th, 2008 @ 11:20 AM

    According to http://stackoverflow.com/questio... it appears this may be caused by a VERSION environment variable already being set.

  • Jean

    Jean September 16th, 2008 @ 11:19 PM

    @Tom : as I explain in the stackoverflow post this is still an error.

    The problem

    at least on windows, and most likely on *nix envs too, when the environment already has a VERSION variable set (and on windows it is case insensitive so Version brings it up too) and VERSION contains some arbitrary string which does not map to an integer, the rake db:migrate command's behaviour is erroneous.

    running it once on an empty database will migrate up, but then running that same command again to solve pending migrations will actually revert the database instead of upgrading it.

    main incriminated files :

    database.rake

    @@@ruby 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

    
    ### migration.rb in active records library
    @@@ruby
    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
    

    the bug is in this line @@@ruby ActiveRecord::Migrator.migrate("db/migrate/", ENV["VERSION"] ? ENV["VERSION"].to_i : nil)

    
    ENV["VERSION"].to_i will return 0 if ENV["VERSION"] is not a valid integer (ruby behaviour). Thus if for some reason the user has a version variable set, it will behave erratically.
    
    # Solutions #
    
    ## The minimal solution ##
    Is to fail loudly when VERSION is not an integer, so that at least the user knows what is wrong and doesn't loose data. for this the code should be changed to be
    @@@ruby
     ActiveRecord::Migrator.migrate("db/migrate/", ENV["VERSION"] ? Integer.new(ENV["VERSION"]) : nil)
    

    A slightly better solution

    at least check that the VERSION is a valid timestamp with respect to the YYYYMMDD format instead of checking for an integer (there may be backward compatibility reasons why you wouldn't want to do that)

    Improved solution

    Actually list the content of the migration directory and ensure that the VERSION is valid for the files in that directory.

    The correct solution

    Do not use environment variables to store program argument ... this is just wrong and you can not make any assumptions as to the existing or non existing environment variables.

  • Frederick Cheung

    Frederick Cheung December 10th, 2008 @ 04:41 PM

    • State changed from “new” to “duplicate”

    Duplicate of #1203 (created later, but has patches)

  • zhuzhu
  • jim123456

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile »

Tickets have moved to Github

The new ticket tracker is available at https://github.com/rails/rails/issues

Shared Ticket Bins

People watching this ticket

Pages