Rails 3: используйте before_create внутри модуля (для моделей ActiveRecord) - PullRequest
2 голосов
/ 22 ноября 2011

Я пишу приложение, в котором многие (но не все) модели ActiveRecord имеют столбец hash. Он заполняется при создании случайным хешем MD5 и используется для ссылки на отдельный объект вместо его идентификатора. Для достижения этого я включил следующий модуль в соответствующие модели и использую find_by_id_or_hash!() во всех контроллерах вместо find:

module IdOrHashFindable

  def self.included(base)
    base.extend(ClassMethods)
  end

  module ClassMethods

    before_create :create_hash             ## <-- THIS FAILS

    # legacy. in use only until find by ID is phased out altogether
    def find_by_id_or_hash!(id_or_hash)
      id_or_hash.to_s.size >= 32 ? find_by_hash!(id_or_hash) : find(id_or_hash)
    end
  end

  def to_param; self.hash end
  def create_hash; self.hash = Support.create_hash  end

end

Чтобы все было сухо, я бы хотел, чтобы вызов before_create также находился внутри модуля. Тем не менее, я продолжаю получать либо

undefined method `before_create' for IdOrHashFindable:Module

или

undefined method `before_create' for IdOrHashFindable::ClassMethods:Module

в зависимости от того, где я его положил. Это имеет смысл (в конце концов, я вызываю функцию, а не определяю ее), но я все же хотел бы знать, как это можно сделать. (Я не могу перезаписать before_create, так как есть другие before_create вызовы).

Кроме того, для всех моделей, в которые включен этот модуль, применяются довольно похожие тесты. Как я последовательно проверяю эту функцию? Я пишу пользовательский блок describe ... end и require его в каждый model_spec.rb, где он применяется? Как передать правильную модель для использования без обращения к глобальным переменным?

Любые идеи приветствуются!

1 Ответ

6 голосов
/ 22 ноября 2011

Вы должны поместить вызов метода класса в class_eval или просто напрямую вызвать его как:

module IdOrHashFindable

  def self.included(base)
    base.extend(ClassMethods)
    base.before_create :create_hash
    # or
    base.class_eval do
      before_create :create_hash
    end
  end

end

потому что когда вы помещаете метод в модуль, он сразу же вызывает его как метод модуля

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...