views:

354

answers:

2

In Rails 3,

I created a table with a migration, then added a column with a migration which creates a has_many, belongs_to relationship....

I then ran rake db:migrate

I'd like to now add an Index because I forgot to add it before I can migrate. can I add that to one of the existing migration files (the create table one) or do I need to create a new migration for adding an index to an existing table?

Thanks

+2  A: 

I usually create a new migration if I forget something like that (especially if I have already migrated in production). But if you are still in development, then you can alter your last migration file and use the redo rake command:

rake db:migrate:redo

There is also:

rake db:rollback  # Rolls the schema back to the previous version (specify steps w/ STEP=n).

Run this command to view all the different rake tasks:

rake -T db

Here is the section in the Rails Guide that talks about it: http://guides.rubyonrails.org/migrations.html#rolling-back

cowboycoded
A: 

If you would like to add your index without losing the data, you must create a new migration to add an index. Assuming your model is called Widget and the foreign model is called Zidget;

rails generate migration AddIndexToWidgets

and inside your new migration file at db/migrate/xxxxxxxxxx_add_index_to_widgets

class AddIndexToWidgets < ActiveRecord::Migration
  def self.up
    change_table :widgets do |t|
      t.index :zidget_id # add ':unique => true' option if necessary
    end
  end

  def self.down
    change_table :widgets do |t|
      t.remove_index :zidget_id
    end
  end
end 

and then rake db:migrate as usual and voilà, you have your indexed column.


Update: If adding an index is all you're doing, there is a more concise way to write the same thing. There is no difference regarding the results. It's just that the former syntax is meant to DRY your code if you have more than one change for your table.

class AddIndexToWidgets < ActiveRecord::Migration
  def self.up
    add_index :widgets, :zidget_id # add ':unique => true' option if necessary
  end

  def self.down
    remove_index :widgets, :column => :zidget_id
  end
end 
edgerunner
Cool. Do you need the change_table part in Rails 3? I got it to work without that?
AnApprentice
It's just one of the possible ways. I edited the answer to include a more concise one. And both of them good for both 2.x and 3
edgerunner