LoginSignup
7

More than 5 years have passed since last update.

すでに動いているシステムでridgepoleを使うためのメモ

Posted at

はじめに

ridgepole はCookpad社が使用しているスキーマ管理ツールです。

スキーマ情報は通常のRailsの schema.rb で使用されているDSLで書かれた Schemafile ファイルで管理され、ここで書かれた定義とDBのスキーマの定義と差分があった場合、DBに差分が適用されるという感じです。

これを使用することによりDBのスキーマを直接変えてからスキーマファイルを生成したり、 rails g migration を実行してできたマイグレーションファイルの増加をなくすことができたり、DBのスキーマ変更をgitのログなどで見ることができたりします。

今回はこの ridgepole を本番に適用するときに役立ちそうなメモを残したいと思います。

Schemafile の作成

まず既存のDBから Schemafile をファイルを生成します。 Schemafile を作成するために以下のコマンドを叩きます。

$  bundle exec ridgepole -c config/database.yml --export --split --output db/schemas/Schemafile

-c でデータベースのコンフィグファイルを指定し、 --exportSchemafile ファイルを出力するようにします。また、 --split を使用することで各テーブルごとに *.schemas ファイルを作成し、 Schemafilerequire することもできます。

ただ --split をすると、外部キーが一番最後に出力されるファイルにまとまってしまうのが謎です。Railsでmigrationファイルを作ってmigrationする時出力される schema.rb も同じなのでそのあたりの仕様に従っているのかもしれません。

このコマンドを叩くときは何も本番環境で実行必要はなく、開発環境で実行すればよいです(開発環境と本番環境でスキーマに差分はないはず・・・)。

外部キーの問題

実施に Schemafile を作成したらまずはデータの入っているステージング環境でテストします(まぁ当たり前の話です)。

ここで多くの人が躓くのは外部キーに名前をつけていない問題です。railsでマイグレーションファイルを作るとき、外部キー制約を記述するのに references を使うと思うのですが、これだと明示的にキーの名前をつけることができず、 出力した Schemafile を使って ridgepole を実行するときエラーになってしまいます。

[ERROR] Foreign key name in `テーブル名` is undefined

Railsでは references で自動的につけた外部キーの名前は fk_rails_ランダムな文字列 になっています。普通に ridgepole を用いて Schemafile を出力すると外部キーの名前は 出力されません 。出力させるためには --dump-with-default-fk-name オプションを付ける必要があります。このオプションを付けると fk_rails_ランダムな文字列 が付与されて外部キーの定義が出力されます。

ところがここで出力した Schemafile を使っていざ適用すると、

[ERROR] Foreign key name in `テーブル名` is undefined

がまた出てしまいます。

ソースを見てみた所、 Schemafile と実際のDBのスキーマの差分を取るところでエラーになっているらしいです。

実際に差分を取っているところは以下の場所です。

ここで expected_definition は読み込んだ Schemafile なので外部キーの定義は書いてあります。問題は current_definition で、これが今のDBに定義されているスキーマを ActiveRecord::SchemaDumper.dump で取得して比較対象を作っています。ここでダンプしてくるときにどうやら外部キーの定義が抜けてしまうようです。

これをなんとかするためにはいったん外部キーを張り直すことで対処しました。


remove_foreign_key :from, :to
add_foreign_key :from, :to, name: 'fk_rails_from_to'

こういうファイルを愚直に作り、外部キーに明示的に名前をつけていきます。

schema.rb に、

add_foreign_key "from", "to", name: "fk_rails_from_to"

のように name が追加されれば大丈夫です。

愚直につけていくしか方法がないように自分は思ったのですが、もし他になにかいいやり方がアレばそちらを採用したいぐらいだるい作業です。

外部キーを張り替えてから再度 ridgepole を実行し、問題なく完了すればOKです。

デプロイ

実際にコマンドで適用できることを確認したら実際のデプロイタスクに組み込みます。

capistrano を使用していたらpluginでよしなにやってくれることを期待してしまいがちですが、あまり良いのがないのでrakeタスクを作ってそれを実行するようにデプロイスクリプトに組み込むのが良いと思います。

rakeタスクを作ってしまえば heroku でデプロイする時に buildpack-ruby-rake-deploy-tasks で実行すれば自動化できて大変良いです。

herokuにDeployしたタイミングでdb:migrateを実行したい

ステージングで確認しているとは言え capistrano を実行して適用するのは緊張感のある作業です。

やってみてどうだったか

増殖するマイグレーションファイルは一掃できましたし、スキーマの変更も楽にできるのが非常に良い感じです。 raild g migration のような便利タスクはないので自分でファイルを作る必要はありますが、それもgeneratorを作ってしまえば解決できる問題だと思います。

ちょっと気になるところとしては、Cookpad社ではDBで直接 ALTER TABLE してから ridgepole でスキーマを出力し、プルリクするというフローでやっているのに対し、自分たちは *.schemas ファイルを追加したり編集したりするフローにしているところで、あまり意図通りの使い方をしていないんじゃないかというところです。

今のところ特に問題は起きていないので大丈夫そうですが、少し気をつけたほうがいいかもしれません。

参考にしたURL

クックパッドにおける最近のActiveRecord運用事情

Ridgepole本番運用における懸念点と解決方法の検討

さらば「rails migrate」、よろしく「ridgepole」

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7