Adding constraints to your application at the database level is a good idea as it provides an extra layer of quality control on top of the data powering your application.

One way to do that is to add default values or constraints—like making sure a field can’t be blank. This is easy to do with Rails’ migrations. But beware…

Instead of…

…adding a column and stipulating a default non-null value all in one go:

class AddComposerToSongs < ActiveRecord :: Migration [ 5.2 ] def change add_column :songs , :composer , :string , default: "Lin-Manuel Miranda" , null: false end end

Use…

…a ‘multiple migration’ strategy to add a field with a constraint to your databases.

Add a column

class AddComposerToSongs < ActiveRecord :: Migration [ 5.2 ] def change add_column :songs , :composer , :string end end

Deploy code that sets default, in your application

class Song < ApplicationRecord before_save :set_default_composer def set_default_composer self . composer = "Lin-Manuel Miranda" if composer . nil? end end

This will catch any code that writes to the database during this intermediate stage.

Using a rake task or using rails console .

Song . where ( composer: nil ). find_each do | song | song . update ( composer: "Lin-Manuel Miranda" ) end

Change the column to have a constraint

class AddRecommendedIndexes < ActiveRecord :: Migration [ 5.1 ] def change change_column :songs , :composer , :string , default: "Lin-Manuel Miranda" , null: false end end

…and then you can delete the Ruby code that sets a default.

But why?

If you take the “all in one” approach you run the risk of significant downtime for your application.

If you set null: false in your migration, the database will rewrite the whole table, locking it whilst doing so. This may take a significant amount of time, depending on how much data you already have stored. Locking your database’s table will likely cause write timeouts for any users trying to write to your database at the same time.

The multi-stage deployment is a bit of a pain, but it enables you to keep the application available for your users during any migration of data tables.

Why not?

If you’re starting a new app or have a very limited dataset.

You might get away with a whole table rewrite and write-lock if you have low amounts of traffic writing to the database. But you would be getting away with it. Chances are you’re going to have some downtime.

If you don’t mind putting your application into maintenance mode, where users are blocked from using the site, you could run the migration with downtime.