ruby 22 lines · 7 steps

How to backfill a column safely in Rails

A batched migration fills a new full_name column without locking the whole users table.

Explained by highlit
1class BackfillUsersFullName < ActiveRecord::Migration[7.1]
2 disable_ddl_transaction!
3 
4 BATCH_SIZE = 5_000
5 
6 class User < ActiveRecord::Base
7 self.table_name = :users
8 end
9 
10 def up
11 User.unscoped.where(full_name: nil).in_batches(of: BATCH_SIZE) do |relation|
12 relation.update_all("full_name = TRIM(CONCAT(first_name, ' ', last_name))")
13 sleep(0.05)
14 end
15 end
16 
17 def down
18 User.unscoped.where.not(full_name: nil).in_batches(of: BATCH_SIZE) do |relation|
19 relation.update_all(full_name: nil)
20 end
21 end
22end
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Backfilling large tables in bounded batches keeps locks short and avoids blocking production traffic.
  2. 2Defining a lightweight model inside the migration insulates it from later changes to the real class.
  3. 3A reversible migration pairs its up-transformation with a down that returns the column to its prior state.

Related explainers

Share this explainer

Here's the card — post it anywhere.

How to backfill a column safely in Rails — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code