Rails の config で設定できる Rails 向け gem を作る
Rails アプリを開発していくと,プラグインやらエンジンやらで何やかんやと gem を作っていくことになります.このようにして作った gem は当然 Rails 向けなので,Rails アプリケーションの config で設定できるようにしたいところです.たとえば,passingloop という gem を作ったとして,この gem で token と email を設定できるとすれば,
Depot::Application.configure do config.passingloop.token = '15x3oegi' config.passingloop.email = 'passingloop@example.com' end
のように書けるようにしたいところです.しかし,このように書くだけでは,
[...]/railties-3.1.1/lib/rails/railtie/configuration.rb:78:in `method_missing': undefined method `passingloop' for #<Rails::Application::Configuration:0x000001017db250> (NoMethodError)
と,config.passingloop が見つからずにエラーになります.そこで,泣く泣く
Depot::Application.configure do config.passingloop_token = '15x3oegi' config.passingloop_email = 'passingloop@example.com' end
と "." を "_" に書き直して逃げたくなるのですが,格好悪いことこの上ありません.そこで,本エントリでは,gem ごとに config が名前空間をつくれるように,すなわち,はじめに紹介した
Depot::Application.configure do config.passingloop.token = '15x3oegi' config.passingloop.email = 'passingloop@example.com' end
のように設定できる gem の作り方を解説します.
答は簡単 Rails::Railtie と ActiveSupport::OrderedOptions
先のエラーメッセージを見れば分かるように,
undefined method `passingloop' for #<Rails::Application::Configuration:0x000001017db250> (NoMethodError)
と,Rails::Application::Configuration なオブジェクトに passingloop が無いことが問題なので追加してあげます.ここでエラーメッセージにある Rails::Application::Configuration なオブジェクトの正体は,Rails::Railtie の config なので,gem で config にキー passingloop を追加してあげます.config.passingloop に追加するオブジェクトに Hash を使ってもいいのですが,
ようにしたいので,ActiveSupport::OrderedOptions を使います.この ActiveSupport::OrderedOptions は,Hash のように使えて,
hash['name'] = 'value' hash['name'] #=> 'value'
と書く代わりに,
ordered_hash.name = 'value' ordered_hash.name #=> 'value'
と書ける優れものです.早速,gem に lib/passingloop/railtie.rb を作成し,
module Passingloop class Railtie < Rails::Railtie config.passingloop = ActiveSupport::OrderedOptions.new end end
lib/passingloop.rb で忘れないように require して,
require "passingloop/version" require "passingloop/railtie" module Passingloop ...
rails c すると,
~/work/depot % rails c Loading development environment (Rails 3.1.1) irb(main):001:0> Depot::Application.configure do irb(main):002:1* puts config.passingloop.email irb(main):003:1> puts config.passingloop.token irb(main):004:1> end passingloop@example.com 15x3oegi => nil
今度はうまくいきました.
Engine と Plugin ならもっと簡単
Rails のエンジンとプラグインは,実は,両方とも Railtie です.ですので,たとえば,Rails エンジンを config で設定可能にするには,Railtie クラスをわざわざ作る必要はなく,Engine クラスの中で config に ActiveSupport::OrderedOptions を設定するだけで ok です.
module Blog class Engine < Rails::Engine isolate_namespace Blog config.blog = ActiveSupport::OrderedOptions.new end end
これは,Blog エンジンの設定を Rails アプリケーションからできるようにする例です.