Nikita Kazakov
Nikita Kazakov
1 min read

Tags

strong_migrations gem prevents large database tables from locking up when running database migrations. The drawback is that instead of running one easy Rails migration, you end up breaking up migrations into three parts.

Here’s how you create a column and add a reference to it, turn it into a foreign key, and run validations using the strong_migrations gem.

Relationship between two tables

Let’s say I want to add a subscription_id column on a tickets table.

First Migration creates the subscription_id column and adds a reference.

def change
  add_reference :tickets, :subscription, index: { algorithm: :concurrently }
end

The second migration adds a foreign key but without validations to avoid locking up the table.

def change
  add_foreign_key :tickets, :subscriptions, validate: false
end

The third migration runs validations.

def change
  validate_foreign_key :tickets, :subscriptions
end

Self Join Example

I have a ticket_files table. I want to add a parent_id column to it and ensure it is a foreign key in Rails. A row in the ticket_files table can be a parent and that parent can have children that are also rows in the ticket_files table.

You’ll need to run 3 different migrations.

First migration creates a parent_id column and references it.

def change  
  add_reference :ticket_files, :parent, index: { algorithm: :concurrently }  
end  

The second migration adds a foreign key to this column and specifically doesn’t validate it so that if the table has millions of rows, it doesn’t lock up.

def change  
  add_foreign_key :ticket_files, :ticket_files, column: :parent_id, validate: false  
end

The third migration validates the new column.

def change  
  validate_foreign_key :ticket_files, column: :parent_id  
end