Ruby on Railsを拡張するGemを作成する等、デフォルトの振る舞いといったものRails.application.configure
で設定できるようにしたいなぁと思ったのですが、config.x
は使わずにネストしたカスタム設定をいい感じに追加する方法をメモ🗒
Railsガイドを見ると以下のような記載があり、基本的にはconfig.foo
の形で直接記載すればいいのですがネストする場合にはhashのkeyとしてアクセスしないといけないので、そういう場合にはconfig.x.foo
みたいな形で定義してあげるのが推奨なのですが、Gem側等の外部からの設定でconfig.x
を使うのはちょっとイマイチかなとも思ったのでいい感じに実装できないのかなぁと思ったのですが、
Railsの設定オブジェクトに独自のコードを設定するには、config.x名前空間またはconfigに直接コードを書きます。両者の重要な違いは、ネストした設定(config.x.nested.nested.hiなど)の場合はconfig.xを使うべきで、単一レベルの設定(config.helloなど)ではconfigだけを使うべきであるという点です。 Rails アプリケーションを設定する - Railsガイド
以下のようなコードを用意して、initializer等々で初期化時に読み込んであげればconfig.foo
の形式でネストしたカスタム設定をいい感じに追加できそうでした🙆♂️
# frozen_string_literal: true require 'active_support' require 'active_support/ordered_options' require 'rails/railtie' module Foo class Configration < ActiveSupport::OrderedOptions def custom_payload(&block) self.custom_payload_method = block end end class Railtie < Rails::Railtie config.foo = Configration.new config.after_initialize do |_app| # NOTE: ユーザーが書き換えた設定値に依存した処理はinitializerによる設定が行われた後に実行するためにここで読み込むなり実行するなりする。 end end end
Hashを継承した動的にaccessor メソッドが定義されるActiveSupport::OrderedOptions
のインスタンスをtopレベルの名前空間config.foo
に渡すことでネストした値でもいい感じにkey形式じゃなくても取得できるようになるということですね✨
ActiveSupport::OrderedOptions < Hash OrderedOptions inherits from Hash and provides dynamic accessor methods. ActiveSupport::OrderedOptions
config.x
の実態であるRails::Application::Configuration::Custom
もmethod_missing
でActiveSupport::OrderedOptions.new
が設定されるようになってるんですね。
module Rails class Application class Configuration class Custom # :nodoc: def initialize @configurations = Hash.new end def method_missing(method, *args) if method.end_with?("=") @configurations[:"#{method[0..-2]}"] = args.first else @configurations.fetch(method) { @configurations[method] = ActiveSupport::OrderedOptions.new } end end def respond_to_missing?(symbol, *) true end end
rails/configuration.rb at v7.0.4.3 · rails/rails · GitHub
便利!