DB のスキーマ情報の差分と闘った話し (Rails)
みなさんこんにちは。
バックエンドエンジニアの豊永です。
今回は Rails を使ってるとよく遭遇すると思われる問題に対して、 Makefile を使って解決した話を共有しようと思います。
何が問題だったか?
Github の Pull Request 機能を利用して複数人でコードレビューを行いながら開発するシーンはよくあるかと思います。その際に、 rails db:migrate
を実行し自分の開発用 DB にレビュー中のコードのスキーマ情報を適用してしまうことは無いでしょうか?
レビュー完了後、そのまま自分の開発に戻り Pull Request を出すと、身に覚えのないテーブル名が db/schema.rb
に記述されていて驚くことがあります。
実は db/schema.rb
は migration ファイルから直接生成されるものではなく、開発用 DB から生成される仕組みになっています。(※ db:migrate
時に RAILS_ENV を明示しない場合)
そのため、レビュー中に適用したスキーマ情報が反映されてしまうのです。
Pull Request で正確なレビューを行うためには、自分の Pull Request には自分が更新した内容のみを含めるべきです。
これを実現するために今までは次の対応を行っていました。
- 空の db 作成
-
db:migrate
を再実行
しかし、レビューが重なると毎回この作業を行う必要がありとても手間です。
解決方法の検討
-
db/schema.rb
を管理対象から外す - 簡単に
db:migrate
を イチから実行出来るようにする
db/schema.rb
を git の管理対象から外す
1. 管理対象から外せば、差分を気にしなくて良くなるので、良い案と思いました。
しかし、以下の懸念があり、この案は不採用としました。
- CI でテーブル作成のタイミングで使っている
- 本当に影響がないのかは分からず、ちょっと怖い
db/schema.rb
を イチから作成出来るようにする
2. 簡単に 先の説明の通り db/schema.rb
は開発用 DB から作成されます。それであれば、空の DB を作成しその DB に対して migration ファイルを順に適用していけば、正しい db/schema.rb
が作成できるはずです。
しかし、Pull Request を出すたびに開発用 DB をクリアするのは現実的ではありません。そこで db/schema.rb
を作り出すためだけの DB を簡単なコマンドで作成できる仕組みを導入しました。
その仕組みを Makefile を使って実現することにしました。
Makefile は、主に再コンパイルのコマンドをまとめておくものになります。
man make
より
The purpose of the make utility is to determine automatically which pieces of a large program need to be recompiled, and issue the commands to recompile them.
今回、再コンパイルではないですが、コマンドをまとめておく用途で使います。
コードの修正
Makefile の抜粋
latest-schema:
echo 'migrate start'
docker-compose exec -e TMP_WORKING_DATABASE='tmp_working' web bundle exec rails \
db:drop \
db:create \
db:migrate
echo 'migrate end'
※ Docker / docker-compose を使っているという前提なので注意してください。
データベース名を外から渡せば、現在使っている開発環境のデータベースも影響を受けることがありません。
config/database.yml の抜粋
development:
<<: *default
database: <%= ENV['TMP_WORKING_DATABASE'] || 'xxxxx_dev' %>
host: <%= ENV['DB_HOST'] || '127.0.0.1' %>
username: xxxxx
password: xxxxx
port: 5432
実行
あとは、db/schema.rb
に意図しない差分ができた時など、db/schema.rb
を綺麗にしたい時にこのコマンドを実行すれば OK です。
$ make latest-schema
まとめ
Makefile といえば C 言語などのコンパイルに利用するイメージがありますが、今回のように一連のコマンド実行をまとめておく用途にも使えます。この Makefile をチームで採用してからは Pull Request 時の不可解なファイル更新に悩まされることなくレビューできるようになりました。
同様の悩みを抱えている方のご参考になれば幸いです。
Discussion