Переопределение методов в модуле ActiveSupport:: Concern, которые определяются методом класса в том же модуле

У меня есть модуль ActiveSupport:: Concern, который выглядит примерно так:

module MyModel
  module Acceptance

    extend ActiveSupport::Concern

    included do
      enum status: [:declined, :accepted]
    end

    def declined!
      self.status = :declined
      # some extra logic
      self.save!
    end

    def accepted!
      self.status = :accepted
      # some extra logic
      self.save!
    end
  end
end

Это только когда-либо будет включено в классы ActiveRecord, следовательно, использование enum. В принципе, я переопределяю методы declined! и accepted!, созданные ActiveRecord::Enum.enum с помощью некоторой дополнительной собственной пользовательской логики.

Проблема в том, что это не работает, потому что когда я вызываю @model.declined!, он просто вызывает исходную реализацию declined! и игнорирует мой пользовательский метод.

Похоже, что мои пользовательские методы включаются в вызывающий класс до, включенный блок выполняется - это означает, что мои пользовательские методы переопределяются теми, которые определены enum, а не другие вокруг.

В этой конкретной ситуации есть несколько простых обходных путей (например, я мог бы переместить вызов enum обратно в класс включения и убедиться, что он выше строки include MyModel::Acceptance, но мне интересно, есть ли способ решить эту проблему проблема, сохраняя все это в одном модуле.

Можно ли каким-либо образом вызвать метод класса в included, который определяет метод экземпляра, а затем переопределить этот метод экземпляра из одного и того же модуля Concern?

Ответ 1

Я думаю, что вы ищете define_method.

module MyModel
  module Acceptance

    extend ActiveSupport::Concern

    included do
      enum status: [:declined, :accepted]

      define_method :declined! do
        self.status = :declined
        # some extra logic
        self.save!
      end

      define_method :accepted! do
        self.status = :accepted
        # some extra logic
        self.save!
      end

    end
  end
end