Railsでconfig/database.ymlを使わずURL文字列でDB接続したい

LINEで送る
Pocket

れこです。今回はRailsネタです。
作ったアプリをHerokuにデプロイするときに、各種アドオンで

のような文字列を環境変数で指定して使うというパターンが有ると思うのですが、
config/database.ymlに一切触らず に、この文字列でDB接続したい…

と思ったのでRailsのソースやドキュメントを読み漁ってみました。

結論

先に結論を書くと、何もせずともDATABASE_URLという名前の環境変数を定義すればOKでした。
config/database.ymlを書き換えたり消したりする必要はなく、環境変数が優先されます。

以下はこの結論に至った経緯とおまけです。

ドキュメントを読んでみる

まずは何事にも公式ドキュメント。

You can connect to the database by setting an environment variable ENV['DATABASE_URL'] or by using a configuration file called config/database.yml.
3.14 Configuring a Database

とあるように、DATABASE_URLという環境変数が使用可能らしいということがわかりました。
ここで気になったのは、 config/database.ymlと環境変数どちらが優先されるのか
ドキュメントだけでは解消しないので詳しく追ってみます。

記事を探してみる

試してみた系記事ないかなーと探してみたらこんな記事が。

John Griffin: Rails 4.1: Database URLs

結局どっちなのかわからん。

Railsのソースを読んでみる

まずはそれっぽいテストがないか確認。
GithubのRailsのソースを検索してみた

このテストこのファイルのテストをみる限り、config/database.ymlよりも環境変数が優先されそうな気がする。

ソースを読んでみるとそれっぽい(?)記述が。

該当ファイルはrails/activerecord/lib/active_record/connection_handling.rb
もしDATABASE_URLという環境変数があれば設定ファイルでいうところの

に相当する処理を内部でやってくれる模様。
ただ、設定ファイルを見てみると

設定ファイルを書き換えるようコメントが書かれていたり、いまいちどっちを信じればよいのかわからない。

実験してみる

英語とRuby力が足らず決定打が見つからなかったので試してみました。
参考記事のコマンドをお借りして試してみます。

  • config/database.yml上ではsqliteで接続するよう設定(gem等も入れとく)
  • ローカルにPostgreSQLは入っていない

という状態で下記コマンドを実行して、ポスグレで接続しようとすれば接続エラーになるはず。
もしconfig/database.ymlが優先されるならSQLiteの接続になるので正しく接続できてしまう

ということで試してみた結果、
config/database.ymlが存在しようと、環境変数が指定されていればそちらが優先される
ということがわかりました。

まとめ

この形式は環境変数1個で事足りるし、.env等に逃がせば接続情報をGit管理しなくて良くなるので、とても好きです。
データベースにかぎらず、RedisやSMTPサーバなんかもこの書式で表現できます。
各DBドライバによって必要な設定のキー名が変わるとか面倒くさくて覚えたくないので、接続系の処理はこの書き方に統一されてしまえばいいのに、なんて思ってます。

RailsアプリはHerokuにデプロイされることが多いからなのか、デフォルトで対応してくれていて助かりました。
さすがRails。といったところなんでしょうか。

ちなみにこの書き方ってなんて名称なんでしょう。
私はurl stringとかconnection stringなんて検索をしているのですが、正しい名前があれば知りたい。。。

おまけ:多言語の対応状況

私がよく触る言語たちの対応状況を調べてみました。

PHP

CakePHPだと対応している模様。
http://book.cakephp.org/3.0/en/development/configuration.html#environment-variables

Laravelだと、この形式でDB接続するのに対応してないので、
この記事のように設定ファイルにPHPの処理を書き加えてLaravelの設定に互換性があるようにパース処理を自前で実装しなきゃいけなかったりクソ面倒です。

FuelPHPも探してみたものの、それらしい記事が見つからず。

Nodejs

新進気鋭のフレームワークAdonisや個人的に好きなORマッパーのobjectionが内部で使用しているknexはもちろん対応しています。

Nodeはフルスタックなフレームワークが少ない(流行ってない)ので、内部的にknexを使ってればOKくらいの認識で居ます

Go

Goは別格です。
あらゆるDBのドライバの根っこになっているdatabase/sqlパッケージがデフォルトで対応しています。
なのでdatabase/sqlパッケージを使わずにオレオレ実装でもしていない限り対応してます。

昔に作ったGoのデモアプリでもこの方式を利用しています。

LINEで送る
Pocket