Nonschema Migrations

See: Github

Nonschema migrations is an old project of mine which I am happy has helped countless teams run data migrations in Rails. This gem, which started its life under a different name, was selected by Github to be in the Github Open Source arctic vault, which means it will be preserved for all of human throughout all of time. In reality, it is unlikely the code in the arctic vault will ever get used, but it represents a long now thinking process that I have identified with since being turned on to the seminal work by Stewart Brand (see Clock of the Long Now, Brand, 1999).

I appreciate that this gem is in the arctic vault and what it implies for how ephemeral our own individual human life is.

As well, this gem deals with time, that is, things changing— it prompts us to think in this fourth dimension. As Stewart Brand would ask, what are we preserving for the 10,000-year view? What knowledge are we passing down as what goes into “the library” that will hold our collective knowledge of this 10,000-year timeframe we are in?

Since the beginning of Rails, you could run anything you wanted in schema migrations. Separate schema-only migrations from nonschema (data) migrations in your Rails app.

Fundamentally, it will shorten the need for downtime deployment while still allowing Rails to reboot in a 12-factor environment (thus reloading its schema table).

As of Rails 6, Rails will automatically reload the schema anyway, obviating the need for this separation. However, that doesn’t mean this gem isn’t useful after Rails 6: There are plenty of times when you want your schema migrations to run immediately and then you want a very long-running data migration to run over the next few hours.

(A huge upgrade involving multiple schema and data changes interlaced — generally a bad practice in large app development— could still take hours & hours on large data sets, leaving your app offline for that time.)

Although I’ve talked about doing all of this at scale (and that’s where nonschema migrations really shine), today I’m just going to show you the most very basic setup.

Let’s assume we have a Person

class Person < ApplicationRecord


Task #1

Our person has a full name “Timothy Edwards”

We want to split this into a first name and last name.

Task #2

Our person has an old-style phone number records: one field for area_code and another for phone number. We’ll want to deprecate the area code field and prepend it to the start of the phone number field.