user3007294
user3007294

Reputation: 951

Updating Attribute Value in Rails Migration

I have over 100 recipes uploaded through ActiveAdmin (http://activeadmin.info/) in with the following attributes:

class CreateRecipes < ActiveRecord::Migration
  def change
    create_table :recipes do |t|
      t.string :title
      t.string :description
      t.string :ingredients
      t.string :position

      t.timestamps
    end
  end
end

I needed to change position from a string to an integer. I was able to do this with the following:

change_column :table_name, :column_name,  :integer  

stackoverflow: Rails migration for change column

The issue is that I do not know how to go back and reassign all the recipes with a position (now that it's an integer). I basically want to start at 0 and go all the way to 100. And if i create a new recipe, it automatically has the position value of 101.

Is there a way to do this without going back and individually changing each recipe?

Upvotes: 1

Views: 1291

Answers (2)

Uilleann
Uilleann

Reputation: 506

You can have the conversion run automatically as part of the migration itself. Add the code to convert the values in the existing records into the migration. Use self.up and self.down to have the appropriate conversion code for that direction of the migration:

class ChangeRecipePositionToInteger < ActiveRecord::Migration
  def self.up
    position_values = Hash[ Recipe.all.map{|r| [r.id, r.position]}]

    change_column :recipes, :position, :integer

    position_values.each_pair do |id, position_value|
      recipe = Recipe.find( id )
      recipe.position = position_value.to_i
      recipe.save
    end
  end

  def self.down
    position_values = Hash[ Recipe.all.map{|r| [r.id, r.position]}]

    change_column :recipes, :position, :string

    position_values.each_pari do |id, position_value|
      recipe = Recipe.find( id )
      recipe.position = position_value.to_s
      recipe.save
    end
  end
end

Upvotes: 0

steve klein
steve klein

Reputation: 2639

It sounds like you want to set :position to :id initially. You could do that through the rails console like so:

recipes = CreateRecipes.all
recipes.each do |recipe|
  recipe.position = recipe.id
end

Then, for new recipes, in your model (create_recipes.rb), you could add:

after_initialize :default_values
...
def default_values
  self.position ||= id
end

Incidentally, this is a nice clean way to handle default or initial values in general. For more information, see this excellent post How can I set default values in ActiveRecord?.

Upvotes: 1

Related Questions