【发布时间】:2015-09-04 16:38:49
【问题描述】:
我在创建包含自定义对象的 array 的 Mongoid 文档时遇到了一些问题。
在我的特殊情况下,我打算存储一个 BaseDevice 对象数组。 BaseDevice 类已经使用 Mongoid 的 custom fields 支持从/到普通哈希进行了修改和序列化。这在单个对象上效果很好。
为了存储BaseDevice 的数组,我创建了以下类:
class BaseDeviceArray < Array
class << self
def demongoize(object)
object ? object.map{ |obj| BaseDevice.demongoize obj } : new
end
def evolve(object)
case
when BaseDeviceArray then object.mongoize
else object
end
end
end
def mongoize
self.map(&:mongoize)
end
end
mongoid 文档长这样
class MongoPeriph
include Mongoid::Document
field :devices, type: BaseDeviceArray
end
假设some_devices 是一个包含两个BaseDevice 实例的数组。
发生的情况如下:当我将some_devices 分配给正常工作的MongoPeriph 实例的设备字段时。
mp = MongoPeriph.create
mp.devices = some_devices
mp.devices # => [#<BaseDevice:0x007fa84bac0080>,#<BaseDevice:0x007fa84baaff78>]
当尝试将push、pop、shift、unshift 方法发送到 mongoid 文档中的 devices 字段时,似乎没有任何反应。更改未出现在 mp 对象上。此外,当按索引引用其中一个对象时(即调用mp.devices[0].some_method 时),世界不会改变。
当从数组中弹出 个对象时,每个pop 都会给出一个新对象。这是意料之中的,因为反序列化程序正在为每个 pop 实例化一个新的 BaseDevice 对象,但内部字段没有更新,即对象停留在那里并且可以无休止地弹出。
使用与 mongoid 文档分开的 BaseDeviceArray 可以按预期工作:
foo = BaseDeviceArray.new
foo << BaseDevice.new
产生一个带有 BaseDevice 对象的数组。
顺便说一句。我在网上找到了另一个approach。这是实现我需要的更通用的方式,但它monkey-patches Mongoid。我试图避免的事情。此外,该解决方案似乎与我的方法存在相同的问题。
【问题讨论】:
-
添加这些关系导致
NoMethodError: undefined method '[]' for nil:NilClass from.../mongoid-4.0.2/lib/mongoid/relations/accessors.rb:113:in 'needs_no_database_query?'似乎它希望我完全“mongoize”带有字段等的BaseDevice(和派生)类。我是什么试图实现的是将普通对象(在数组中)嵌入到mongoid文档中。 -
我不知道究竟是什么使对象能够将其嵌入文档中。我认为,存在 de/mogoize 方法应该使其成为“合格”的 mongo 对象。与此同时,我或多或少地使用了嵌入式关系。我忘记在
BaseDeviceinitializer 中添加super,这让mongoid 偏离了轨道。包括Mongoid::Attributes::Dynamic之后,它似乎工作了。无论如何,我宁愿拥有没有所有 Mongo 混乱的“普通”对象。