作っている Rails エンジンの設定を外からやりたくて、どうやるのがいいのかな?と調べてみました。要は、エンジンの挙動をコントロールするための変数なりをエンジンに用意しておいて、マウントする側の親アプリケーションから値を設定したいということですね。
RailsGuides に書いてある方法
RailsGuides のエンジンチュートリアルで紹介されているのは、エンジンのモジュールに mattr_accessor
を設定しておいて、親アプリからそのアクセサを介してモジュール変数 (モジュールのクラス変数というべき?) にその値を設定するという方法です。
lib/myengine.rb (エンジン側)
mattr_accessor :something
config/initializers/myengine.rb (親アプリ側)
Myengine.something = "Something Cool"
簡単だし、これでやりたいことは実現可能なのですが、モジュールの名前空間の直下に各設定がそのまま置かれるので、数が増えてくるとゴチャゴチャしそうです。できれば Myengine.config.something
のような形にしたい。もちろん config
というを何か専用のクラスのインスタンスにしたり、ハッシュにしたりすればすぐにできるんですが、どんどんオレオレ設定になっていくのが嫌なのでもっと標準的な方法にしたいところ。
def configure; yield self; end
ってカッコいいな!
たまたま、Refile という gem のコードを眺めていたらこんなのがありました。
module Refile
...
class << self
...
# Yield the Refile module as a convenience for configuring multiple
# config options at once.
#
# @yield Refile
def configure
yield self
end
...
end
Refile.configure do |config|
config.direct_upload = ["cache"]
config.allow_origin = "*"
config.logger = Logger.new(STDOUT)
config.mount_point = "attachments"
config.automount = true
config.content_max_age = 60 * 60 * 24 * 365
config.types[:image] = Refile::Type.new(:image, content_type: %w[image/jpeg image/gif image/png])
end
おぉ、これ何かカッコいい!
やっていること自体は上記した RailsGuides に書かれている方法と同じなのですが、単純に self
を引数にしてブロックを実行する configure
メソッドを定義することで、Refile.configure
ブロック経由でアクセスできるようになってるですね。ちょっと感動しました。この記事を書いたのはこれを記録しておきたかったためです。ぶっちゃけ。
ActiveSupport::Configurable
ActiveSupport::Configurable
というモジュールがあります。エンジンの設定の場合も、このモジュールが提供する機能を利用するのが一番わかりやすいんじゃないかと思います。
lib/myengine/config.rb (エンジン側)
module Bigmouth
class Config
include ActiveSupport::Configurable
config_accessor :something
configure do |config|
config.something = "Something Special"
end
end
end
config/initializers/myengine.rb (親アプリ側)
Myengine.configure do |config|
config.something = "Something Cool"
end if defined?(Myengine)
結局は Config
専用のクラスを作る必要があるので、コード量は少し多くなってしまいます。しかし、Rails の ActiveSupport が標準で提供するインターフェースを使えるのは大きなメリットだと思います。また、ちゃんと確認してはいませんが、コードを少し読んでみたところでは、親クラスの設定を継承することもできるような感じに見えました。必要になることがあれば確認してみたいと思います。