はじめに
Web アプリでマルチテナントをやる場合、 すべてのテーブルに tenant_id を追加してデータを分けるのではなく、 テナントごとにデータベースを分けたい。
データベースを分けておけば、バグで他のテナントのデータまで変更してしまう可能性を減らせる。
データベースを分けたマルチテナントをサポートする、 『Apartment』という gem を使った記事を以前書いた。
Heroku 上での運営を考えているので、 Heroku 上でもテナントごとにデータベースを分けたマルチテナントが可能か試してみた。
なお、Heroku Postgres を使うから、厳密にはテナントごとにスキーマを分けることになる。
Heroku にデプロイ
Rails + Apartment でマルチテナントな Web サービスを作る - present で作成した Rails プロジェクトを使うことが前提。 git で Heroku に push する。
$ git remote add heroku git@heroku.com:tnakamura-sandbox.git $ git push heroku master
テナント作成
テナントを登録するテーブルが必要なので、まずマイグレーションを実行する。
$ heroku run bundle exec rake db:migrate
Heroku 上で rails console を実行し、テスト用のテナントを登録する。
$ heroku run bundle exec rails console irb(main)001:0> Tenant.create(name:"foobar") irb(main)002:0> Tenant.create(name:"hogefuga")
テナントのスキーマを作成
テナントを登録したので、各テナントのスキーマを Heroku Postgres 上に作成。 その後、各スキーマにマイグレーションを実行する。
$ heroku run bundle exec rake apartment:create $ heroku run bundle exec rake db:migrate
今回は rake タスクで実行したけど、スキーマの作成と削除は Tenant のコールバックにしたほうが良さそうだ。
サブドメインを登録
Qiita::Team みたいに、テナントごとに異なるサブドメインを使いたい。
テナントが増えるたびにサブドメインを登録するのは手間なので、 例えば次のような、ワイルドカードのサブドメインを登録する。
cname *.yourdomain.jp tnakamura-sandbox.herokuapp.com.
自分はバリュードメインを使っているので、バリュードメインで設定した。 末尾のピリオドは必須。これを忘れたせいで、1日潰してしまった。要注意。
Heroku にドメインを追加
バリュードメインで登録した、ワイルドカードのサブドメインを Heroku に追加する。
$ heroku domains:add *.yourdomain.jp
これで、例えば foobar.yourdomain.jp と hogefuga.yourdomain.jp で、 Heroku 上の Rails アプリにアクセスできる。
Heroku 上でテナントごとにスキーマが違っているか確認
Web ブラウザで、まず foobar のサブドメインにアクセス(実際のドメイン名は都合により隠している)。
サインアップしてみる。
ログイン後のトップページにユーザーの一覧が表示された。
次に hogefuga のサブドメインにアクセス。
サブドメインが違うので、こちらではまだログインしていない状態になっている。
こちらでもサインアップしてみる。
すると、ユーザー一覧にはサインアップしたユーザーだけが表示された。
ちゃんとテナントごとにスキーマが分かれているようだ。
まとめ
ワイルドカードのサブドメインを使っているので、 テナントごとに異なるサブドメインを使える。
また、Apartment を使っているので、サブドメインごとにスキーマを分けることができた。 結果、テナントごとにスキーマを分けることに成功。