首先,假设我对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
不幸的是,我仍然遇到同样的错误。
答案 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
)