Help us understand the problem. What is going on with this article?

Railsの設定定数をYAMLで一元管理する(EasySettings)

More than 3 years have passed since last update.

はじめに

Railsの設定定数をYAMLファイルで管理するのにEasySettingsというGemを使う方法です。

使い方

Gemfile

gem "easy_settings"

を追加して、config/settings.ymlに次のようなYAMLファイルを作ります。

default: &default
  key1: value1

development:
  <<: *default
  key2: value2.d

test:
  <<: *default
  key2: value2.t

production:
  <<: *default
  key2: value2.p

あとはアプリのどこからでも次のようにして値を参照できます。

EasySettings.key2 #=> "value2.d"

他の定数管理

他にもいろいろあります。

Settingslogic

Settingslogicはこの中でも最もシンプルで1つのYAMLで定数を管理します。
機能といえばERBが処理できることとファイル内で名前空間が設定できることぐらいです。

Settingslogicクラスを継承したクラスを定義する必要があります。

EasySettingsは元々Settingslogicの代替として作られたためSettingslogicに似ています。

Config

元々はrails_configというGemだったようです。

複数のYAMLファイルに継承関係を持たせて定数を定義できます。

Chamber

Chamber is the auto-encrypting, extremely organizable, Heroku-loving, CLI-having, non-extra-repo-needing, non-Rails-specific-ing, CI-serving configuration management library.

だそうです。ドキュメントも多くてやりたいことに対して大げさすぎる気がするのであんまり調べてません。

特徴

といっても機能はそんなにありません。EasySettingsはただのYAMLを読み込むHashie::Mashです。
Settingslogicの不満点を解消するために作ったのでSettingslogicと比較しながら説明します。

メソッド形式、ハッシュ形式(String、Symbol)で参照できる

これはSettingslogicでもできますね。

例えば設定ファイルがこんな感じだと、

development:
  key1:
    subkey1: value1
    subkey2: value2

こんな感じで参照できます。

>> EasySettings.key1
=> #<EasySettings subkey1="value1" subkey2="value2">
>> EasySettings[:key1]
=> #<EasySettings subkey1="value1" subkey2="value2">
>> EasySettings["key1"]
=> #<EasySettings subkey1="value1" subkey2="value2">
>> EasySettings.key1.to_h
=> {"subkey1"=>"value1", "subkey2"=>"value2"}

>> EasySettings.key1.subkey1
=> "value1"
>> EasySettings.key1[:subkey1]
=> "value1"
>> EasySettings.key1["subkey1"]
=> "value1"

ハッシュはEasySettingsのオブジェクトになりますがto_hHashオブジェクトに変換できます。

初期化いらず

Settingslogicはどこかで次のようにクラスを定義する必要があります。

class Settings < Settingslogic
  source Rails.root.join("config/settings.yml").to_s
  namespace Rails.env
end

EasySettingsは不要です。あえていうならGemfileに1行必要なぐらい。

未定義のメソッド形式で例外が発生しない

Settingslogicでは定義されていないキーをメソッド形式で参照しようとすると例外が発生します。

# Settingslogicは例外発生
>> Settings.undefined_key
Settingslogic::MissingSetting: Missing setting 'undefined_key' in /tmp/app/config/settings.yml

# EasySettingsはnilになる
>> EasySettings.undefined_key
=> nil

EasySettingsの場合メソッド形式で代入もできます。

# Settingslogicだとエラー
>> Settings.existed_key = "new value"
Settingslogic::MissingSetting: Missing setting 'existed_key=' in /tmp/app/config/settings.yml

# EasySettingsはOK
>> EasySettings.existed_key = "new value"
=> "hoge"

デフォルト値が設定できる

デフォルト値が設定できます。機能的には一番強力かもしれません。

例えばこういうときに、

class User < ActiveRecord::Base
  paginates_per(Settings[:per_page] || 5)
end

EasySettingsではこのように書けます。

class User < ActiveRecord::Base
  paginates_per EasySettings.per_page(5)
end

さらに、EasySettingsでは末尾に!をつけるとキーが定義されていない場合だけハッシュとして初期化します。

>> EasySettings.new_key
=> nil
>> EasySettings.has_key?(:new_key)
=> false
>> EasySettings.new_key!
=> #<EasySettings>
>> EasySettings.has_key.to_h
=> {}
>> EasySettings.has_key?(:new_key)
=> true

EasySettings.new_key({})EasySettings.new_key!は同じ意味です。

これは設定に入れ子ハッシュがある場合に威力を発揮します。
例えばpaginates_perをYAMLでは次のように書きたい時、

development:
  pagination:
    per_page: 5

これを次のように書いてしまうと、paginationがnilの場合エラーになります。

pagenates_per(Settings[:pagination][:per_page] || 5)

なので、最低でもYAMLファイルに空ハッシュを書くようにするか、

development:
  pagination: {}

アプリ側をこのようにする必要があります。

paginates_per((Settings[:pagination] || {})[:per_page] || 5)

やってられませんね。EasySettingsならこうです。

pagenates_per EasySettings.pagination!.per_page(5)

別名が使える

EasySettingsという名前は長いです。短くしたいという時はこうします。

Config = EasySettings

config/initializers/easy_settings.rbとかに書いておけばいいと思います。

config/settings.yml以外

config/settings.yml以外を使いたい場合、EasySettings.source_file=メソッドで設定ファイルを指定します。
ついでに紹介しておくと、EasySettings.namespace=とかEasySettings.reload!とかいうのもあります。

config/initializers/easy_settings.rbに次のように書くと環境ごとにYAMLファイルを切り替えられます。

config/initializers/easy_settings.rb
EasySettings.source_file = Rails.root.join("config/settings/#{Rails.env}.yml")
EasySettings.namespace = nil
EasySettings.reload!

Config = EasySettings

ERBが使える

ERBを処理できます。

default: &default
  aws_id: <%= ENV["AWS_ID"] %>
  aws_secret: <%= ENV["AWS_SECRET"] %>

みたいな感じです。dotenvと組み合わせられます。

Rails以外でも使える

元々はRails以外で使うために作りました。
Rails以外で使うとき、Dir.pwdからみてsettings.ymlconfig/settings.ymlにファイルが存在すればそれを読むようになっています。
それ以外に設定ファイルがあるときはEasySettings.source_file=を使って下さい。

その他Settingslogicのおかしな挙動

ついでなので、他にもレアケースですがSettingslogicにおかしな挙動があってハマりました。

例えばデフォルト値を設定してその後も使い回す例です。

>> (Settings[:pagination] ||= {})[:per_page] ||= 5
=> 5
>> Settings[:pagination][:per_page]
=> nil

あと入れ子になるハッシュで同じキーを突っ込んだ場合。

>> Settings[:foo] = {foo: "bar"}
=> {:foo=>"bar"}
>> Settings.foo
=> {:foo=>"bar"}
>> Settings.foo.foo
Settingslogic::MissingSetting: Missing setting 'foo' in /tmp/app/config/settings.yml

おわりに

最後はSettingslogicディスみたいになってしまいましたが、基本はSettingslogicのシンプルなところをリスペクトして作ったGemです。
設定管理のお供にいかがでしょうか:smile::sparkles:

wondershake
株式会社Wondershake(ワンダーシェイク)は30代前後の女性をターゲットにしたLocari(ロカリ)というメディアの開発と運営を行っている会社です。
http://wondershake.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした