高木のブログ

Rails.env.production?の正体

2022/01/20

環境によって処理を分ける時によく使う Rails.env.production? だったり、Rails.env.development? ってやつ

Rails.env.production?
#=> true

タイポしてもエラーにならないから、何事だ!と思い少し調べた

Rails.env.productio?
#=> false

そもそも String じゃなかった

Rails.env がただの Stirng かと思ったら、ActiveSupport::EnvironmentInquirer だった

Rails.env
#=> "production"
Rails.env.class
#=> ActiveSupport::EnvironmentInquirer

ActiveSupport::EnvironmentInquirer とは

ごにょごにょ書いてあるけど、一旦ここでは ActiveSupport::StringInquirer を継承しているとだけ

module ActiveSupport
  class EnvironmentInquirer < StringInquirer # :nodoc:
    DEFAULT_ENVIRONMENTS = ["development", "test", "production"]
    def initialize(env)
      super(env)

      DEFAULT_ENVIRONMENTS.each do |default|
        instance_variable_set :"@#{default}", env == default
      end
    end

    DEFAULT_ENVIRONMENTS.each do |env|
      class_eval "def #{env}?; @#{env}; end"
    end
  end
end

https://github.com/rails/rails/blob/18707ab17fa492eb25ad2e8f9818a320dc20b823/activesupport/lib/active_support/environment_inquirer.rb

ActiveSupport::StringInquirer とは

String を継承して、method_missing をオーバーライドしている

module ActiveSupport
  class StringInquirer < String
    private
      def respond_to_missing?(method_name, include_private = false)
        method_name.end_with?("?") || super
      end

      def method_missing(method_name, *arguments)
        if method_name.end_with?("?")
          self == method_name[0..-2]
        else
          super
        end
      end
  end
end

https://github.com/rails/rails/blob/18707ab17fa492eb25ad2e8f9818a320dc20b823/activesupport/lib/active_support/string_inquirer.rb#L19

最後に ? が付く存在しないメソッドが呼ばれた時、 ? の前までの文字列と自身の文字列が一致しているかを比較するようになっている

vehicle = ActiveSupport::StringInquirer.new('car')
#=> "car"
vehicle.car? # "car" == "car"
#=> true
vehicle.bike? # "car" == "bike"
#=> false

これが Rails.env.production? の正体だった

補足

String#inquiry メソッドとは

文字列をStringInquirerオブジェクトに変換するメソッド
Railsであればすぐに使える、Active Supportの String 拡張

'production'.inquiry.production?
#=> true
'production'.inquiry.class
#=> ActiveSupport::StringInquirer

参考


ytkg

Written by ytkg, Twitter, GitHub