2019-05-06

一つのDBを複数のrailsアプリから利用する

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
RailsにAPIや管理画面やバッチツールなど、いろいろ機能が盛り込まれて大きくなってきて、それぞれの機能を分離したくなってきてみました。
この段階では、
app
という一つのリポジトリがある感じです。

分離自体は、役割が結構ちゃんとわかれていたので、それほど大変ではありませんでした。
この段階では、
app_api
app_admin
app_batch
のような三つのリポジトリがある感じです。

三つに別れましたが、共通のDBを利用する必要があって、分離されたアプリそれぞれにmigrationがあって、それをなんか変わったときに人手で同期させていたのですが、それぞれ独自にカラム追加したりして、だんだん見通しが悪くなってきて、ちょっと面倒になってきました。

dbを独立したリポジトリにしてよい感じで使えないかなぁと調べていたら、
というのがあることを知りました。
Ridgepoleでは、migrationのように変更を積み重ねるのではなく、最終的なテーブル定義を保持していて、dbとテーブル定義の差分を見て、dbを変更していく感じです。
dbの状態の見通しがよくなりそうだし、定義ファイルを独立したリポジトリで管理して、それぞれのリポジトリのsubmoduleとして取り込むとよさげかなと思ってみました。

というわけで、そのような環境を構築してみます。

以下を参考にしています。
https://re-engines.com/2017/05/03/370/#rails_migrateRidgepole-2

まずはGemfileに
gem 'ridgepole'
を追加して
bundle install
します。これでRidgepoleが利用できるようになります。

現在のdb定義からRidgepole用の定義ファイルを生成します。
bundle exec ridgepole -c config/database.yml -E development --split --export -o db/schemas/Schemafile

これで
db/schemas/
以下に定義ファイルが作成されます。

試しに定義ファイルの適用コマンドを試します。
bundle exec ridgepole -c config/database.yml -E development --apply -f db/schemas/Schemafile
当然、変更はありません。
念のため、test環境にも試します。
bundle exec ridgepole -c config/database.yml -E test --apply -f db/schemas/Schemafile
こちらも変更はありません。

ここまでくれば、migrationは不要になるので思い切って削除します。
rm -r db/migrate

あと、rspecのテストのために以下の変更もしたほうがよいようです。
spec/rails_helper.rb
の中の
ActiveRecord::Migration.maintain_test_schema!
の部分をコメントアウトします。
以下のような感じです。

#begin
#  ActiveRecord::Migration.maintain_test_schema!
#rescue ActiveRecord::PendingMigrationError => e
#  puts e.to_s.strip
#  exit 1
#end

とりあえず、ここでmigrationからRidgepoleに切り替えた感じになります。
Ridgepoleをより便利に使えるようにします。
以下を参考にしています。
https://qiita.com/ToqTock/items/c185a38fd4e2011ddd64

まずmigrationファイルを生成されないようにします。Myappの部分は環境にあわせて変えてください。
config/initializers/generator.rb



Ridgepoleのコマンドが長いのでdb:migrateのようにdb:applyみたいな感じを使えるようにします。
lib/tasks/ridgepole_tasks.rake



ここからdbの部分を以下のような感じで独自のリポジトリにします。
cp -pr db ~/app_db
cd ~/app_db
git init
git add *
git commit
git remote add origin app_db用リポジトリ
git push -u origin master
これで
app_api
app_admin
app_batch
app_db
の4つのリポジトリができましたが、この段階では、app_dbと同じ内容が個別にapp_apiなどにある感じです。

app_apiなどの各アプリのdbディレクトリgitのsubmoduleを利用してapp_dbのリポジトリを見るようにします。
git submoduleに関しては、以下が参考になりました。
https://qiita.com/sotarok/items/0d525e568a6088f6f6bb

cd ~/app_api
この中のdbディレクトリを削除してしまいます。
rm -r db
ここで以下のコマンドを実行してapp_dbをsubmoduleにしてdbに結び付けます。
git submodule add app_db用リポジトリ db
これでリポジトリは、以下のような感じになりました。
app_api(dbフォルダはapp_db)
app_admin(dbフォルダはapp_db)
app_batch(dbフォルダはapp_db)
app_db

これでそれぞれのアプリでdbに変更したものは、app_dbを介して、それぞれに配布できるようになりました。