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

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

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.ActiveRecord::Migration 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,