【Ruby on Rails】 gem を使わないで環境毎に定数管理をする

概要

Ruby on Rails には定数管理用の gem がたくさん存在します。

有名な gem だと以下の名前が上がるかと思います。

github.com

github.com

  • config は環境毎に yaml ファイルを用意して定数を管理するので、大規模アプリケーション向けのイメージがあります。管理する定数が多い場合にオススメです。
  • settingslogic は 1 つの yaml ファイルで環境毎に定数を管理するので、中小規模アプリケーション向けのイメージがあります。管理する定数が少ないのであれば見やすくてオススメです。

ただ、ここで『定数管理ぐらい自分で実装できないのか?』と疑問に思ったことがあります。

そこで今回、自分で簡単に実装できる環境毎に定数を管理する方法をまとめました。

 

はじめに

gem を使わない定数管理方法だと、以下の 2 つがオーソドックスな方法かと思います。

  • application_controller.rb で定数を管理する方法
  • config/initializers/constants.rb のようなファイルを用意して、そこで定数を管理する方法

application_controller.rb はアプリケーション共通の処理を管理する場所なので、ここで定数を管理するのはあまり相応しくないと思います。

config/initializers/constants.rb のようにファイルを用意して、そこで定数を管理する方法は賛成です。

ただし ruby ファイルではなく、環境毎に設定を管理しやすい yaml ファイルを利用しようと思います。

 

Yaml を利用した定数管理

用意するファイルは以下の2 つです。

  • config/constants.yml
  • config/initializers/00_load_config.rb

config/constants.yml

これが定数を管理するためのファイルです。

yaml の機能であるアンカーとエイリアスを利用して、環境毎に定数を出し分けています。

common の設定をベースに development と production で設定を上書きしている感じです。

# アプリケーション共通の設定を記載します
common: &common
  domain:
    example: http://example.com/
    port:
      - 80
      - 443
  message: This is application common setting

# 開発環境の設定を記載します
development:
  <<: *common
  message: This is development environment setting

# 本番環境の設定を記載します
production:
  <<: *common
  message: This is production environment setting

config/initializers/00_load_config.rb

これは先程の /config/constants.yml に記載した設定をアプリケーション起動時に読み込んで、ruby で扱える定数に変換しています。

file = "#{Rails.root}/config/constants.yml"

# 再帰的にオブジェクトを凍結します
def deep_freeze(hash)
  hash.freeze.each_value do |i|
    i.kind_of?(Hash) ? deep_freeze(i) : i.freeze
  end
end

CONFIG = deep_freeze(YAML.load_file(file)[Rails.env].deep_symbolize_keys)

 

deep_symbolize_keys は再帰的にシンボル形式に変換してくれます。

https://apidock.com/rails/v4.0.2/Hash/deep_symbolize_keys

freeze は オブジェクトを凍結、つまり変更不可 (定数) にします。

http://ref.xaio.jp/ruby/classes/object/freeze

 

動作確認

期待通り定数が取得出来ることをコンソール経由で試してみます。

設定した定数は以下のように CONFIG で呼び出す事が出来ます。

$ rails c
Loading development environment (Rails 5.0.2)
irb(main):001:0> CONFIG
=> {:domain=>{:example=>"http://example.com/", :port=>[80, 443]}, :message=>"This is development environment setting"}

# 開発環境用の設定に上書きされています
irb(main):002:0> CONFIG[:message]
=> "This is development environment setting"

# 凍結されています
irb(main):003:0> CONFIG.frozen?
=> true

# ネストした値も凍結されています
irb(main):004:0> CONFIG[:domain][:exapmle].frozen?
=> true 

# 変更しようとするとエラーになります
irb(main):005:0> CONFIG[:message] << 'Hello'
RuntimeError: can't modify frozen String

 

まとめ

gem を使わずに環境毎に定数管理する方法をまとめました。

割と簡単に出来たかなと思います。

自分で実装することのメリットはこの 2 つかなと思います。

  • 仕様を把握できる点
  • 自分で拡張できる点

あとは gem の依存関係などでどうしても定数管理用の gem をインストール出来ない場合などは使えると思います。

ただし、1 つの yaml ファイルで全ての定数を管理するので、中小規模アプリケーション向けの方法だと思います。

Ruby on Rails の定数管理方法に答えはないと思います。

どの方法も一長一短なので、開発しているアプリケーションに合った方法を見極めて採用するのがいいと思います。