DEV Community

Shivashankar
Shivashankar

Posted on

Catch unsafe rails db migrations with strong_migrations gem

Introduction

In rails we are using migrations for performing database structure/schema modifications.

While doing so, we may end with many unsafe migrations. We shall go for strong_migrations gem to make sure we write safe migrations.

It is also helpful to force the entire team to follow it as a best practice.

Step: 1 Add strong_migrations to Gemfile
  gem 'strong_migrations'

Note: Do not add the gem under any group.

 $ bundle install
 $ rails generate strong_migrations:install 
Step 2: checking the strong migrations
$ rails g scaffold User name:string{50} email
$ rake db:migrate
Adding column with default value
$ rails g migration add_status_to_users status:integer 

update db/migrate/20200615103121_add_status_to_users.rb

class AddStatusToUsers < ActiveRecord::Migration[6.0]
  def change
    add_column :users, :status, :integer, default: 1
  end
end
$ rake db:migrate

When we attempt to migrate the above migration it throws error as follows

rake aborted!
StandardError: An error has occurred, all later migrations canceled:

=== Dangerous operation detected #strong_migrations ===

Adding a column with a non-null default causes the entire table to be rewritten.
Instead, add the column without a default value, then change the default.

class AddStatusToUsers < ActiveRecord::Migration[6.0]
  def up
    add_column :users, :status, :integer
    change_column_default :users, :status, 1
  end

  def down
    remove_column :users, :status
  end
end

Then backfill the existing rows in the Rails console or a separate migration with disable_ddl_transaction!.

class BackfillAddStatusToUsers < ActiveRecord::Migration[6.0]
  disable_ddl_transaction!

  def up
    User.unscoped.in_batches do |relation|
      relation.update_all status: 1
      sleep(0.01)
    end
  end
end

strong_migrations not only report the issue, it gives the suggestions as well, which is one of the most important notable feature.

Discussion (0)