Rails 3:在模块中使用'before_create'(对于ActiveRecord模型)

时间:2011-11-22 06:25:13

标签: ruby ruby-on-rails-3 activerecord module

我正在编写一个应用程序,其中许多(但不是全部)ActiveRecord模型都有hash列。这是使用随机MD5哈希创建时填充的,用于引用单个对象而不是其ID。为实现此目的,我在相应的模型中包含了以下模块,并在所有控制器中使用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 个答案:

答案 0 :(得分:6)

您必须在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

因为当你将方法放在模块中时,它会直接调用它作为模块的方法