Techioz Blog

define_method の「module」ブロック内でメソッド呼び出しを使用できないのはなぜですか?

概要

attr_reader - type_slugs (文字列の配列を返す) を備えたモデルクラスがあり、これを使用していくつかのメソッドを生成したいと考えています。

例えば:

module Orders
  module Extensions
    module Order
      module TypeCheckable
        extend ::ActiveSupport::Concern

        ::Orders::Config.type_slugs.each do |type|
          define_method("#{type}_order_type?") { order_type == type }
        end
      end
    end
  end
end

例えば:

次のようなモデルメソッドを使用すると、同じエラーが発生します。

some_method_defined_in_model.each do |type|
  define_method("#{type}_order_type?") { order_type == type }
end

しかし、単語配列を使用すると問題なく動作します

%w(message product another).each do |type|
  define_method("#{type}_order_type?") { order_type == type }
end

この場合、Orders::Config.type_slugs を使用することは可能ですか?そうでない場合、なぜそうなるのでしょうか?

解決策

提供された情報から、モジュール Orders::Config には type_slugs メソッドがないことがわかります。

コードを機能させたい場合は、次のように定義する必要があります。

module Orders
  module Config
    def self.type_slugs
      %w[message product another]
    end
  end
end

または、そのリストが動的に変更されない場合は、次のようになります。

module Orders
  module Config
    TYPE_SLUGS = %w[message product another].freeze
  end
end

その場合は、::Orders::Config.type_slugs を ::Orders::Config::TYPE_SLUGS に変更します。

Rails を使用する場合は、たとえば、付属のメソッドを使用する必要があります

module Orders
  module Extensions
    module Order
      module TypeCheckable
        extend ::ActiveSupport::Concern

        included do
          ::Orders::Config::TYPE_SLUGS.each do |type|
            define_method("#{type}_order_type?") { order_type == type }
          end
        end
      end
    end
  end
end

その後、モデルで使用できるようになります

class SuperOrder < ApplicationRecord
  include Orders::Extensions::Order::TypeCheckable
end

class BestOrder < ApplicationRecord
  include Orders::Extensions::Order::TypeCheckable
end

そして、このようなメソッドを呼び出します

SuperOrder.new.product_order_type? # compare super order type with "product"
BestOrder.new.message_order_type? # compare best order type with "message"