Railsには RAILS_ENV
と呼ばれる環境を切り替えるための環境変数が用意されています. 最初はこれだけでも十分ですが開発が進むと環境毎に切り替えるプロジェクトがよくあるので備忘録として自分がよくやる対応をまとめてみました.
config_for
config/database.yml
の様に環境毎で切り替える設定はconfig_forというメソッドがあるのでこれを使うとスッキリ書けます.
Rails6 であれば、 shared
でマージされるのでデフォルト値が手軽に設定できます.
Rails5を使ってるのであれば、YAMLのAnchors and Aliasesを使ってマージすると便利です.
# config/foo.yml
---
shared:
key3: 'shared value'
base: &base
env: <%= Rails.env %>
key1: "<%= ENV['MY_APP_KEY1'] || 'default' %>"
key2: 'hello %{user_cd}'
production:
<<: *base
# config/application.rb
module MyApp
class Application < Rails::Application
config.foo = config_for(:foo).deep_symbolize_keys
end
end
### ruby
Rails.configuration.foo[:key1]
# => default
Rails.configuration.foo[:key2].gsub('%{user_cd}', 'dummy1')
# => hello dummy1
Rails.configuration.foo[:key3]
# => shared value # if Rails6
# => nil # if Rails5
設定より規約を活用して設定を減らす
普通にconfig_forを使ってるとYAMLの設定ファイルの運用が進むにつれて数が増えてきます.
もしくは、既存のシステムがあるとすれば既に膨大な設定になってるかと思います.
そこで設定より規約を使って最初から規約寄りにしておいた方が良いでしょう.
YAMLでは値にkey1: null
とあるとNULL
値(Rubyだとnil
)になります. key1: 'null'
の様にクォートで囲むと文字列の"null"
になります.
これを利用して以下の様にしていきます.
# config/foo.yml
---
production:
key1: <%= "'#{ENV['MY_APP_KEY1']}'" || 'null' %>
# config/application.rb
module MyApp
class Application < Rails::Application
config.foo = config_for(:foo).deep_symbolize_keys
end
end
### something ruby implements
def config_foo_key1
"${Rails.configuration.foo[:key1] || 'default'}"
end
config_foo_key1
の様に実装側にデフォルト値を用意することで、YAMLの設定ファイル自体がコンパクトになります. base
やshared
にデフォルト値を寄せても良いと思います.
このケースの良いところは全ての環境が規約だけで運用できる様になった時、YAMLファイルが不要になるところにあります. 既存のハードコードされた設定があるのであれば、これらの方法を使って減らしていくと良いと思います.
-
bundle exec rails runner -e development 'puts config_foo_key1
'default'
-
MY_APP_KEY1=foo bundle exec rails runner -e production 'puts config_foo_key1
'foo'
環境変数にも規約をつける
アプリで固有で使う環境変数にも MY_APP_KEY1
の様に接頭辞MY_APP_
の様に規約をつけると良いでしょう.
grepした時に探すのも楽になるし、直感的にアプリ固有の環境変数だということがわかります.
環境毎にユニークな名前空間を使う
ここでの名前空間は以下の様なものを指しています.
-
AWS S3
のバケット名 - ディレクトリのパス
- データベース名
- 全文検索のインデックス名
- キャッシュのキー名
通常、プロダクション環境だと、複数環境が相乗りになることは無いはずですが、デモ環境や開発環境は複数環境が相乗りになることがあります.
含める変数
Railsでは 環境変数 RAILS_ENV
があるし、parallel_tests では ENV['TEST_ENV_NUMBER']
を使って並列に動作できるようにしています. さらにアプリ固有の環境変数もある場合もあります.
これらを含めた名前空間にすることで開発環境の様に development
とtest
が同じPCで動かせる様になります.
例えばS3のオブジェクトのキーを考えてみましょう. 環境変数とデモ環境などの実際に動作する物理的な環境であれば MY_APP_ENV
の値には demo
,prd
,stg
, qa
そして dev
の様な値が入るとします.
名前空間は "#{Rails.env}#{ENV['TEST_ENV_NUMBER']}/${ENV['MY_APP_ENV']}"
の様な規約にしておきます.
これらの変数の組み合わせが展開されると以下の様になります. 名前空間が重なってないため柔軟に同じサーバや開発環境内に同居できる様になります.
RAILS_ENV | TEST_ENV_NUMBER | MY_APP_ENV | name space |
---|---|---|---|
development | dev | development/dev |
|
production | demo | production/demo |
|
production | prd | production/prd |
|
production | stg | production/stg |
|
production | qa | production/qa |
|
test | dev | test/dev |
|
test | 2 | dev | test2/dev |