通过_type字段实例化mongoid子类

时间:2013-08-27 18:27:34

标签: ruby-on-rails ruby mongodb mongoid

从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
    ...

有谁知道实现这个目标的正确方法?

2 个答案:

答案 0 :(得分: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)

答案 1 :(得分:1)

在查看Mongoid源代码后,我意识到Mongoid确实尝试在查看_type字段时实例化正确的类型,当有人做这样的事情时:

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

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

class Base
  Descendant1.inspect
  Descendant2.inspect
  ...

是的,这真的很痛苦,但它允许你使用Rails重新加载你的课程。