Rails: How can I rename a database column in a Ruby on Rails migration?

Rails: How can I rename a database column in a Ruby on Rails migration?

rename_column :table, :old_column, :new_column

Youll probably want to create a separate migration to do this. (Rename FixColumnName as you will.):

script/generate migration FixColumnName
# creates  db/migrate/xxxxxxxxxx_fix_column_name.rb

Then edit the migration to do your will:

# db/migrate/xxxxxxxxxx_fix_column_name.rb
class FixColumnName < ActiveRecord::Migration
  def self.up
    rename_column :table_name, :old_column, :new_column
  end

  def self.down
    # rename back if you need or do something else or do nothing
  end
end

For Rails 3.1 use:

While, the up and down methods still apply, Rails 3.1 receives a change method that knows how to migrate your database and reverse it when the migration is rolled back without the need to write a separate down method.

See Active Record Migrations for more information.

rails g migration FixColumnName

class FixColumnName < ActiveRecord::Migration
  def change
    rename_column :table_name, :old_column, :new_column
  end
end

If you happen to have a whole bunch of columns to rename, or something that would have required repeating the table name over and over again:

rename_column :table_name, :old_column1, :new_column1
rename_column :table_name, :old_column2, :new_column2
...

You could use change_table to keep things a little neater:

class FixColumnNames < ActiveRecord::Migration
  def change
    change_table :table_name do |t|
      t.rename :old_column1, :new_column1
      t.rename :old_column2, :new_column2
      ...
    end
  end
end

Then just db:migrate as usual or however you go about your business.


For Rails 4:

While creating a Migration for renaming a column, Rails 4 generates a change method instead of up and down as mentioned in the above section. The generated change method is:

$ > rails g migration ChangeColumnName

which will create a migration file similar to:

class ChangeColumnName < ActiveRecord::Migration
  def change
    rename_column :table_name, :old_column, :new_column
  end
end

In my opinion, in this case, its better to use rake db:rollback, then edit your migration and again run rake db:migrate.

However, if you have data in the column you dont want to lose, then use rename_column.

Rails: How can I rename a database column in a Ruby on Rails migration?

If the column is already populated with data and live in production, Id recommend a step by step approach, so as to avoid downtime in production while waiting for the migrations.

First Id create a db migration to add columns with the new name(s) and populate them with the values from the old column name.

class AddCorrectColumnNames < ActiveRecord::Migration
  def up
    add_column :table, :correct_name_column_one, :string
    add_column :table, :correct_name_column_two, :string

    puts Updating correctly named columns
    execute UPDATE table_name SET correct_name_column_one = old_name_column_one, correct_name_column_two = old_name_column_two
    end
  end

  def down
    remove_column :table, :correct_name_column_one
    remove_column :table, :correct_name_column_two
  end
end

Then Id commit just that change, and push the change into production.

git commit -m adding columns with correct name

Then once the commit has been pushed into production, Id run.

Production $ bundle exec rake db:migrate

Then Id update all of the views/controllers that referenced the old column name to the new column name. Run through my test suite, and commit just those changes. (After making sure it was working locally and passing all tests first!)

git commit -m using correct column name instead of old stinky bad column name

Then Id push that commit to production.

At this point you can remove the original column without worrying about any sort of downtime associated with the migration itself.

class RemoveBadColumnNames < ActiveRecord::Migration
  def up
    remove_column :table, :old_name_column_one
    remove_column :table, :old_name_column_two
  end

  def down
    add_column :table, :old_name_column_one, :string
    add_column :table, :old_name_column_two, :string
  end
end

Then push this latest migration to production and run bundle exec rake db:migrate in the background.

I realize this is a bit more involved of a process, but Id rather do this than have issues with my production migration.

Leave a Reply

Your email address will not be published.