Jenorish
Jenorish

Reputation: 1714

Migrate postgresql database to uuid rails 3.1

I am using rails 3.1 and ruby 1.9.3,Now i want to use uuid concept in rails 3 so i did like :-

create_table :posts, :id => false do |t|
 t.string :uuid, :limit => 36, :primary => true
end

ActiveRecord::Base.class_eval do
 set_primary_key 'uuid'
 before_create :generate_uuid
 def generate_uuid
 self.id = UUIDTools::UUID.random_create.to_s
 end
end

This is working for new data,now i want to migrate existing data with relation.for uuid they are using datatype as string,in postgresql the data type used for primary_key and foreign key is integer ,so if i am trying to change foreign key integer to string it is throwing error.

Could you please tell me some example,how to do this.

kingston.s

Upvotes: 0

Views: 1665

Answers (1)

Matt Beedle
Matt Beedle

Reputation: 171

First of all, to use UUIDs in ActiveRecord you need to enable the uuid-ossp extension. Create a new migration.

class EnableUuidOssp < ActiveRecord::Migration
  def change
    enable_extension 'uuid-ossp'
  end
end

Second, you do do not need to use string type in your migrations, there is a uuid type. When creating a new table:

create_table :posts, id: :uuid do |t|
end

This will automatically generate a UUID in the same way that an incremental Integer ID is normally generated. When you want to add a UUID field to an existing table:

change_table :posts do |t|
  t.uuid :uuid, default: 'uuid_generate_v4()'
end

The default: 'uuid_generate_v4()' will ensure that a new UUID is generated for you by Postgres.

Third, to actually migrate existing data I guess you would need to create migrations that 1) add UUID fields to all of the models 2) create new UUID foreign keys 3) associate the models using the UUID foreign keys 4) remove the old foreign keys 5) rename the new foreign keys:

class AddUuidToPosts < ActiveRecord::Migration
  def change
    change_table :posts do |t|
      t.uuid :uuid, default: 'uuid_generate_v4()'
    end
  end
end

# assuming you have a comments table that belongs to posts
class AddUuidToComments < ActiveRecord::Migration
  def change
    change_table :comments do |t|
      t.uuid :uuid, default: 'uuid_generate_v4()'
    end
  end
end

class AssociateCommentsWithPostings < ActiveRecord::Migration
  def change
    # Add a uuid_posting_id field to comments relate comments to postings
    # through the posting UUID
    change_table :comments do |t|
      t.uuid :uuid_posting_id
    end

    # Loop through all existing postings and update all associated comments
    # new foreign key field
    Posting.all.each do |posting|
      # Not sure about this, but you might need to touch the posting to generate
      # a UUID
      posting.touch 

      Comment.where(posting_id: posting.id).
        update_all(uuid_posting_id: posting.uuid)
    end

    remove_column :comments, :posting_id
    rename_column :comments, :uuid_posting_id, :posting_id
  end
end

# You don't need to override ActiveRecord::Base to set the primary key to :uuid.
# Only do this in existing models that you migrated to UUIDs. In any new tables
# that you create, the id column will be a UUID, as long as you use the migration
# format that I showed you at the top.
class Posting < ActiveRecord::Base
  set_primary_key :uuid
end

You should probably go the extra mile and actually remove the old Integer id fields and rename the new UUID ids to "id" but I'm not sure how to do that off the top of my head. Anyway, I think this approach should work. There could be a couple of errors or bits missing though, it's a bit late over here.

Upvotes: 2

Related Questions