Chetan
Chetan

Reputation: 48011

Rails migration: use different column as id

I'm just starting to learn Rails migrations. I have a table called tags with a column name [string] (and with the auto-generated id column). I want to migrate it so that the table uses the name column as the id and primary key. How do I do this making sure all existing records work with the new schema?

Upvotes: 1

Views: 2034

Answers (1)

user483040
user483040

Reputation:

The approach is straightforward, but the execution seems risky. getting the migration up working is fairly straight forward, but the down? not sure.

  1. Make sure that your name column is unique across all records
  2. Find all other objects that store a reference to your object and change those from id to name.

If you find that the column is not unique you'll have to come up with some kind of plan to change that...like name+id in the name field for duplicates or something similar. All of this can be done from a migration, of course.

I suggest leaving the id column there but only use it to resolve issues you find along the way

By way of example, assume this is your model around the tags table:

class Tag < ActiveRecord::Base
end

Assume you have at least this other model, Thing, that has a simple association with the Tag model:

class Thing < ActiveRecord::Base
   has_one :tag
end

There is a tag_id column on the things table. I'd add a column called tag_name, change the association to have a foreign key pointing to this new column...

class Thing < ActiveRecord::Base
  has_one :tag, :foreign_key => "tag_name"
end

This tells Rails that the association between these things is through the new column. By convention it would look for "tag_id".

Given this change you can go into the migration and:

add_column :things, :tag_name, :string

Thing.all.each do |thing| 
  if thing.tag
    thing.tag_name = thing.tag.name
  end
end

remove_column :things, :tag_id

This is a quick and dirty example and I might have missed something. the key thing is to add the new column, move the association, remove the old column.

There are other scenarios like the case where the model is involved in a many to many association or some polymorphic association, but the general approach would be similar in those cases.

Upvotes: 3

Related Questions