れこです。今回はRailsネタです。
作ったアプリをHerokuにデプロイするときに、各種アドオンで
XXX_URL=pg://xxx:yyy@zzz/hoge
のような文字列を環境変数で指定して使うというパターンが有ると思うのですが、
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 calledconfig/database.yml
.
3.14 Configuring a Database
とあるように、DATABASE_URL
という環境変数が使用可能らしいということがわかりました。
ここで気になったのは、 config/database.ymlと環境変数どちらが優先されるのか 。
ドキュメントだけでは解消しないので詳しく追ってみます。
試してみた系記事ないかなーと探してみたらこんな記事が。
結局どっちなのかわからん。
まずはそれっぽいテストがないか確認。
GithubのRailsのソースを検索してみた。
このテストとこのファイルのテストをみる限り、config/database.ymlよりも環境変数が優先されそうな気がする。
ソースを読んでみるとそれっぽい(?)記述が。
# Returns fully resolved connection hashes.
# Merges connection information from `ENV['DATABASE_URL']` if available.
def resolve
ConnectionAdapters::ConnectionSpecification::Resolver.new(config).resolve_all
end
private
def config
@raw_config.dup.tap do |cfg|
if url = ENV["DATABASE_URL"]
cfg[@env] ||= {}
cfg[@env]["url"] ||= url
end
end
end
該当ファイルはrails/activerecord/lib/active_record/connection_handling.rb。
もしDATABASE_URLという環境変数があれば設定ファイルでいうところの
development: # ※ここは実行時の環境による
url: <%%= ENV['DATABASE_URL'] %>
に相当する処理を内部でやってくれる模様。
ただ、設定ファイルを見てみると
# On Heroku and other platform providers, you may have a full connection URL
# available as an environment variable. For example:
#
# DATABASE_URL="postgres://myuser:mypass@localhost/somedatabase"
#
# You can use this database configuration with:
#
# production:
# url: <%%= ENV['DATABASE_URL'] %>
#
と設定ファイルを書き換えるようコメントが書かれていたり、いまいちどっちを信じればよいのかわからない。
英語とRuby力が足らず決定打が見つからなかったので試してみました。
参考記事のコマンドをお借りして試してみます。
という状態で下記コマンドを実行して、ポスグレで接続しようとすれば接続エラーになるはず。
もしconfig/database.ymlが優先されるならSQLiteの接続になるので正しく接続できてしまう
# 接続エラー(ポスグレで接続しようとしている)
DATABASE_URL=postgresql://localhost/app_development bundle exec rails s
# 接続できた(config/database.ymlは間違ってない)
bundle exec rails s
ということで試してみた結果、
config/database.ymlが存在しようと、環境変数が指定されていればそちらが優先される
ということがわかりました。
この形式は環境変数1個で事足りるし、.env等に逃がせば接続情報をGit管理しなくて良くなるので、とても好きです。
データベースにかぎらず、RedisやSMTPサーバなんかもこの書式で表現できます。
各DBドライバによって必要な設定のキー名が変わるとか面倒くさくて覚えたくないので、接続系の処理はこの書き方に統一されてしまえばいいのに、なんて思ってます。
RailsアプリはHerokuにデプロイされることが多いからなのか、デフォルトで対応してくれていて助かりました。
さすがRails。といったところなんでしょうか。
ちなみにこの書き方ってなんて名称なんでしょう。
私はurl string
とかconnection string
なんて検索をしているのですが、正しい名前があれば知りたい。。。
私がよく触る言語たちの対応状況を調べてみました。
CakePHPだと対応している模様。
http://book.cakephp.org/3.0/en/development/configuration.html#environment-variables
Laravelだと、この形式でDB接続するのに対応してないので、
この記事のように設定ファイルにPHPの処理を書き加えてLaravelの設定に互換性があるようにパース処理を自前で実装しなきゃいけなかったりクソ面倒です。
FuelPHPも探してみたものの、それらしい記事が見つからず。
新進気鋭のフレームワークAdonisや個人的に好きなO/Rマッパーのobjectionが内部で使用しているknexはもちろん対応しています。
Nodeはフルスタックなフレームワークが少ない(流行ってない)ので、内部的にknexを使ってればOKくらいの認識で居ます
Goは別格です。
あらゆるDBのドライバの根っこになっているdatabase/sqlパッケージがデフォルトで対応しています。
なのでdatabase/sqlパッケージを使わずにオレオレ実装でもしていない限り対応してます。
昔に作ったGoのデモアプリでもこの方式を利用しています。