4

从 Mongoid 文档中,我看到如果我有以下内容:

class Base
  include Mongoid::Document
end
class InheritedA < Base
end
class InheritedB < Base
end

我可以执行以下操作,这将与“_type”属性一起存储。

a = InheritedA.new
a.save

Mongoid 将创建以下文档。

{ _type: "InheritedA" }

我的问题是,稍后我有一个只有 String _type 值的函数,我希望实例化正确的类型。我试过这个:

Base.new({ _type: mytype });

然而,Mongoid 认为这是一个动态属性并拒绝它。我知道打开动态属性不是正确的做法,因为我不想在一般情况下允许这种行为。

我想避免做这样的事情:

ob = nil
if mytype == "InheritedA"
  ob = InheritedA.new
elsif
    ...

有谁知道完成此任务的正确方法?

4

2 回答 2

3

有两种方法可以解决这个问题。第一个创建基类文档,然后将其转换为子类文档。使用此方法,您只能根据基类中定义的字段进行初始化:

# attributes = {base_key1: value1, base_key2: value2}
Base.new(attributes).becomes(mytype.constantize)

第二个直接创建子类的文档,您可以为子类初始化任何字段:

# attributes = {base_key1: value1, base_key2: value2, sub_key3: value3}
Mongoid::Factory.build(mytype.constantize, attributes)
于 2013-08-29T12:42:08.057 回答
1

在查看了 Mongoid 源代码后,我意识到 Mongoid 确实会尝试根据 _type 字段来实例化正确的类型,当人们执行以下操作时:

Base.new({ _type: "InheritedA" })

它通过查看基类的后代来做到这一点。显然我的 ruby​​ 类正在被延迟加载,默认情况下 Base.descendants 调用返回一个空列表!我不确定这是否是由于使用了 JRuby,或者关于 Rails 开发模式的怪癖,或者 config.cache_classes 值,或者其他原因,但我能够通过这样做来解决它:

class Base
  Descendant1.inspect
  Descendant2.inspect
  ...

是的,这确实很痛苦,但它允许您使用 Rails 重新加载您的类。

于 2013-09-07T00:27:49.680 回答