如何在模块中调用此类方法?

时间:2012-12-15 19:36:47

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

首先,假设我对Ruby对象模型的理解非常不完整,来自C,PHP和Java。

现在,我的应用程序包含多个模型共享的功能,因此我尝试将该功能移动到模块中以保持干燥。每个模型都有一个需要序列化的“数据”属性。但是,当我将serialize调用移动到模块中时,我无法使其工作。这是基本模型:

class MyModel < ActiveRecord::Base
  include MyApp::Data
end

这是模块:

module MyApp
  module Data
    serialize :data, ActiveRecord::Coders::Hstore

    def get_data(key)
      data && data[key]
    end

    def set_data(key, value)
      self.data = (data || {}).merge(key => value)
    end
  end
end

当我尝试实例化包含MyApp:Data的模型时,出现以下错误:

NoMethodError: undefined method `serialize' for MyApp::Data:Module

如何实现这一点,以便在实例化MyModel时,只需包含data即可序列化MyApp::Data属性?

编辑:

我也试过这个:

module MyApp
  module Data
    def self.included(base)
      base.extend(ClassMethods)
    end

    module ClassMethods
      serialize :data, ActiveRecord::Coders::Hstore
    end

    def get_data(key)
      data && data[key]
    end

    def set_data(key, value)
      self.data = (data || {}).merge(key => value)
    end
  end
end

不幸的是,我仍然遇到同样的错误。

1 个答案:

答案 0 :(得分:2)

正如您所写,在加载模块时会调用serialize。对serialize的方法调用没有接收器,因此它是在Data模块上进行的。另一方面,您希望在包含该模块的类上调用它。

您可以使用self.included挂钩执行此操作 - 只要包含模块并且执行包含的类作为参数传递,就会调用它,例如

module Data
  def self.included(base)
    base.serialize ...
  end
end

使用activesupport,您也可以

module Data
  extend ActiveSupport::Concern

  included do
    serialize :data, ...
  end
end

它设置了self.included for you并评估块,使self成为包含类,而不是模块(如果你想调用的方法碰巧被保护/私有,它可以很方便 - dsl stuff isn当它充满base.send :blah

时可读