How to change a reference column to be polymorphic?

Update for Rails >= 4.2

Current Rails generates references with index and foreign_key, which is a good thing.
This means that the answer of @Christian Rolle is no longer valid as after renaming foo_id it leaves a foreign_key on bars.fooable_id referencing foo.id which is invalid for other fooables.

Luckily, also the migrations evolve, so undoable migrations for references do exist.

Instead of renaming the reference id, you need to create a new reference and remove the old one.
What's new is the need to migrate the ids from the old reference to the new one.
This could be done by a

Bar.find_each { |bar| bar.update fooable_id: bar.foo_id }

but this can be very slow when there are already many relations. Bar.update_all does it on database level, which is much faster.

Of course, you should be able to roll back the migration, so when using foreign_keys the complete migration is:

def change
  add_reference :bars, :fooable, polymorphic: true
  reversible do |dir|
    dir.up { Bar.update_all("fooable_id = foo_id, fooable_type='Foo'") }
    dir.down { Bar.update_all('foo_id = fooable_id') }
  end
  remove_reference :bars, :foo, index: true, foreign_key: true
end

Remember that during rollback, change is processed from bottom to top, so foo_id is created before the update_all and everything is fine.


1. Change the name of foo_id to fooable_id by renaming it in a migration like:

rename_column :bars, :foo_id, :fooable_id

2. and add polymorphism to it by adding the required foo_type column in a migration:

add_column :bars, :fooable_type, :string

3. and in your model:

class Bar < ActiveRecord::Base
  belongs_to :fooable, 
    polymorphic: true
end

4. Finally seed the type of you already associated type like:

Bar.update_all(fooable_type: 'Foo')

Read Define polymorphic ActiveRecord model association!