Heroku でマルチテナントな Rails アプリを実現する

はじめに

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 のサブドメインにアクセス(実際のドメイン名は都合により隠している)。

f:id:griefworker:20140725215141p:plain

サインアップしてみる。

f:id:griefworker:20140725215209p:plain

ログイン後のトップページにユーザーの一覧が表示された。

次に hogefuga のサブドメインにアクセス。

f:id:griefworker:20140725215238p:plain

サブドメインが違うので、こちらではまだログインしていない状態になっている。

こちらでもサインアップしてみる。

f:id:griefworker:20140725215320p:plain

すると、ユーザー一覧にはサインアップしたユーザーだけが表示された。

f:id:griefworker:20140725215353p:plain

ちゃんとテナントごとにスキーマが分かれているようだ。

まとめ

ワイルドカードサブドメインを使っているので、 テナントごとに異なるサブドメインを使える。

また、Apartment を使っているので、サブドメインごとにスキーマを分けることができた。 結果、テナントごとにスキーマを分けることに成功。

ワイルドカードサブドメインと Apartment を使うことで、 Heroku でもマルチテナントを実現できた。