Rails ActiveSupport: проблема, вызывающая исключение при включении, если модель не отвечает_to? некоторые методы

#ruby-on-rails #activesupport-concern

#ruby-on-rails #activesupport-проблема

Вопрос:

Я кодирую проблему Rails, которая будет добавлена к нескольким моделям. Для дополнительной безопасности я хочу убедиться, что все модели, в которые включена эта проблема, реагируют на некоторые методы экземпляра. Назовите это контрактом, если хотите.

В любом случае, вот код, который, как я ожидал, будет работать:

 module SomeConcern

  extend ActiveSupport::Concern

  included do

    raise("The model has to respond to some_instance_method") if !self.method_defined?(:some_instance_method)

  end

end
 

Однако это исключение всегда возникает.

  • Проблемы обычно (из-за стилей) включаются в верхнюю часть модели; однако на данный момент мы еще не достигли def вызова в модели, поэтому метод экземпляра еще не определен.
  • Даже если мы включим проблему в самый низ модели (чего я действительно хотел бы избежать для лучшего взаимодействия с разработчиками), я заметил, что if some_instance_method на самом деле является именем столбца, он будет реагировать только true method_defined? в том случае, если я создам экземпляр модели заранее.

С a binding.pry внутри included блока это происходит:

 self.method_defined?(:some_column_name)
=> false

self.new

self.method_defined?(:some_column_name)
=> true
 

Итак, учитывая все это, каков наилучший способ вызвать исключение, когда проблема включена в модель, чтобы убедиться, что один экземпляр этой модели действительно реагирует на некоторые методы, которые я хочу проверить?

Ответ №1:

Вы могли бы определить значение по умолчанию some_instance_method в SomeConcern , какая raise ошибка при его вызове, если у вас нет метода с тем же именем в SomeModal :

 module SomeConcern
  extend ActiveSupport::Concern

  def some_instance_method
    raise("The model has to respond to some_instance_method")
  end
end

class SomeModal
  include SomeConcern

  def some_instance_method
    do_the_work
  end
end