複数環境に対応したRailsアプリケーションの設定方法

Ruby

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の設定ファイル自体がコンパクトになります. baseshared にデフォルト値を寄せても良いと思います.

このケースの良いところは全ての環境が規約だけで運用できる様になった時、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'] を使って並列に動作できるようにしています. さらにアプリ固有の環境変数もある場合もあります.

これらを含めた名前空間にすることで開発環境の様に developmenttestが同じ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
タイトルとURLをコピーしました