1

首先,假设我对 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

我如何使它在我实例化时MyModeldata通过简单地包含来序列化属性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

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

4

1 回答 1

2

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

您可以使用self.included钩子来执行此操作 - 每当包含模块并且正在执行包含的类作为参数传递时都会调用它,例如

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

有了主动支持,您还可以

module Data
  extend ActiveSupport::Concern

  included do
    serialize :data, ...
  end
end

它为您设置 self.included 并评估该块,以便 self 成为包含类,而不是模块(如果您要调用的方法恰好是受保护/私有的,这可能很方便 - dsl 的东西不是充满时可读base.send :blah

于 2012-12-15T19:47:36.567 回答