This article is a part of MoneyForward Tech Blogathon 2022.
Hello, I'm pocke. I work for Accounting Plus (クラウド会計Plus) as a Web Backend Engineer. I work as a Ruby Committer to maintain RBS too.
Today I'll introduce a gem, strong_migrations, which is my favorite gem.
This article was originally written in Japanese, and I translated it myself.
What is strong_migrations
strong_migration is a gem to detect dangerous migrations.
Database migration can often be dangerous. For example, it blocks writing to the database depending on DDL. Changing table definitions may cause unexpected behavior on your application.
This gem detects such dangerous migrations.
How to use
It's easy. Add strong_migrations
to your Gemfile
, then execute bundle install
and bin/rails generate strong_migrations:install
.
Only with the above processes, dangerous migrations fail automatically by this gem.
If you want to suppress the error, you can wrap the migration with safety_assured { add_column ... }
block.
Problems detected by strong_migrations
All of the problems are listed in the README. For example, deleting a column and adding a column with a default value are good examples to understand this gem.
This gem is for a Rails application, but the most checked problems are RDBMS problems, which don't depend on Rails. I recommend looking at the problems list even if you do not develop Rails applications.
Why strong_migrations is great
Detecting dangerous migrations is valuable, but personally, I think it is the most valuable part of this gem. The most valuable part is the detailed descriptions.
Let's look at the error message of adding a column with a default value. The following code causes an error by Strong Migrations.
class AddTitleToArticle < ActiveRecord::Migration[7.0] def change add_column :articles, :title, :string, default: '' end end
The error message is the following.
=== Dangerous operation detected #strong_migrations === Adding a column with a non-null default blocks reads and writes while the entire table is rewritten. Instead, add the column without a default value, then change the default. class AddTitleToArticle < ActiveRecord::Migration[7.0] def up add_column :articles, :title, :string change_column_default :articles, :title, "" end def down remove_column :articles, :title end end Then backfill the existing rows in the Rails console or a separate migration with disable_ddl_transaction!. class BackfillAddTitleToArticle < ActiveRecord::Migration[7.0] disable_ddl_transaction! def up Article.unscoped.in_batches do |relation| relation.update_all title: "" sleep(0.01) end end end
As you can see, the error message is very detailed. This message includes the following items.
- What is the problem.
- Why the problem will cause.
- How should you treat this problem.
In this message, the three items correspond to the following sentences.
- WHAT:
Adding a column with a non-null default
- WHY:
It blocks reads and writes while the entire table is rewritten
- HOW: The suggested code snippets
The user can easily understand the problem and how to solve it through this message. If you got the message, you could solve the problem only with the message. No google is needed in many cases.
Such tools tend to have not enough messages, but this gem displays enough messages to solve the problem. I want to follow this style when I create such a tool.
Conclusion
I introduced the strong_migrations gem. You can install this gem easily, and you'll gain safety migrations.
I also describe the kindness of this gem. I love this gem because of its kindness.
Let's install this gem to your Rails application!
マネーフォワードでは、エンジニアを募集しています。 ご応募お待ちしています。
【会社情報】 ■Wantedly ■株式会社マネーフォワード ■福岡開発拠点 ■関西開発拠点(大阪/京都)
【SNS】 ■マネーフォワード公式note ■Twitter - 【公式】マネーフォワード ■Twitter - Money Forward Developers ■connpass - マネーフォワード ■YouTube - Money Forward Developers