Migration commits when run by itself (db:migrate:up), but not with other migrations (db:migrate)

I have a migration that saves correctly to the database when it's run
by itself through db:migrate:up, but not when it's run with other
migrations through db:migrate.

class SetActiveOnExistingItems < ActiveRecord::Migration
  def self.up
    Item.all.each do |item|
      if item.item_status == Item::STATUS_REVIEW
        item.active = false
      elsif item.item_status == Item::STATUS_IN_PROGRESS
        item.active = false
      else
        item.active = true
      end
      puts "setting item_id = #{item.id} to active = #{item.active}"
      item.save!
      puts "setting item_id = #{item.id} to active = #{item.active}"
      item = Item.find(item.id)
      puts "setting item_id = #{item.id} to active = #{item.active}"
    end
  end

  def self.down
    Item.all.each {|item| item.active = nil; item.save(false)}
  end
end

The output during db:migrate is:
setting item_id = 1 to active = true # (this one is before the save)
setting item_id = 1 to active = true # (this one is after the save)
setting item_id = 1 to active = # (this one is after the lookup)
...

During db:migrate:up, it works as expected:
setting item_id = 1 to active = true
setting item_id = 1 to active = true
setting item_id = 1 to active = true
...

For some reason, the data appears to not be actually committed to the
database during db:migrate, while it is during db:migrate:up. There's
no exception thrown by save!, no indicator that I can see that the
save is unsuccessful. Even if it was, why would it only be
unsuccessful during a regular migration run, and not during
db:migrate:up?

Has anyone seen this before? Do you have any idea what could cause
this?

Thanks.

Sorry, I should have mentioned - the migration before it is one where
that active column is added. The migration after alters a column in a
different table. The column is definitely added before this migration
runs.

I tried doing the whole thing in one migration - adding the column and
setting the value, and I got the exact same behavior with this
migration:

class AddActiveToItems < ActiveRecord::Migration
  def self.up
    add_column :items, :active, :boolean
    Item.all.each do |item|
      if item.item_status == Item::STATUS_REVIEW or item.item_status
== Item::STATUS_IN_PROGRESS
        item.active = false
      else
        item.active = true
      end
      item.save!
      puts "id: #{item.id}, active: #{item.active}"
      puts "id: #{item.id}, active: #{Item.find(item.id).active}"
    end
  end

  def self.down
    remove_column :items, :active
  end
end

for db:migrate:
id: 1, active: true
id: 1, active:

for db:migrate:up:
id: 1, active: true
id: 1, active: true

There must be something weird about this data manipulation.

You need to put "Item.reset_column_information" at the top of the
migration so Rails reloads the altered table.

Jarin Udom
Robot Mode LLC
http://robotmo.de

Oh also "Item.reset_column_information" needs to be after the
add_column and before the Item.all.each if you are adding the column
and manipulating the data in the same migration. If it is 2 separate
migrations, just put it at the top of the 2nd one.

Jarin Udom
Robot Mode LLC
http://robotmo.de

Sure enough, I see that exact information in the Migration documentation. http://api.rubyonrails.org/classes/ActiveRecord/Migration.html

It works great now. Thank you.

Adam

You should also be careful about using model classes in migrations -
because your source is updated in one go but migrations run one by one
it's easy enough to run into trouble. For example if your model has a
validation on a column that is added by migration two and migration
one tries to create some objects of that class then it will fail
because of the validation on the not yet existent column

Fred

Frederick Cheung wrote:

Sure enough, I see that exact information in the Migration documentation.http://api.rubyonrails.org/classes/ActiveRecord/Migration.html
It works great now. Thank you.

You should also be careful about using model classes in migrations -
because your source is updated in one go but migrations run one by one
it's easy enough to run into trouble. For example if your model has a
validation on a column that is added by migration two and migration
one tries to create some objects of that class then it will fail
because of the validation on the not yet existent column

And this is why it's now considered preferable to use rake
db:schema:load when setting up a server from scratch. Migrations are
primarily for migration

Fred

Best,