2013-08-27 2 views
4

Из документов Mongoid я вижу, что если у меня есть следующий:Instantiate Mongoid подклассов по _Type поля

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

я могу сделать следующее, которые будут храниться с «_Type» атрибутом.

a = InheritedA.new 
a.save 

Mongoid создаст следующий документ.

{ _type: "InheritedA" } 

Моя проблема заключается в том, что в дальнейшем у меня есть функция, которая имеет только значение _Type String, и я хотел бы создать экземпляр соответствующего типа. Я пробовал:

Base.new({ _type: mytype }); 

Однако Mongoid считает, что это динамический признак и отклоняет его. Я знаю, что включение динамических атрибутов - это не правильный курс, потому что я не хочу допускать такое поведение в общем случае.

Я хочу, чтобы избежать необходимости делать что-то вроде этого:

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

Кто-нибудь знает правильный метод для достижения этого?

+0

Я думаю, что это работает как конструировано. Если вы хотите создать тип 'InheritedA', вы должны называть' InheritedA.new'. Но этот человек решил это, вызвав необработанное обновление MongoDB: http://stackoverflow.com/questions/5306646/how-to-change-a-documents-type-in-mongoid – GSP

ответ

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) 
+0

Это все еще полагается на меня с фактическим классом а не только значение String _type, не так ли? – Erich

+1

Я предположил, что у вас есть строка в 'mytype'. '[constantize] (http://apidock.com/rails/v3.2.13/String/constantize)' преобразует строку в соответствующий класс. – rubish

+0

+1 для '# constantize'. '{_type:" InheritedA "} [: _ type] .constantize.new' совпадает с' InheritedA.new'. – Sim

1

После просматривая источник Монгоида, я понял, что Монгоид действительно пытается создать подходящий тип, основываясь на взгляде на поле типа _type, когда вы делаете что-то вроде этого:

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

Он делает это, глядя на потомков базового класса. По-видимому, мои классы ruby ​​ленивы загружаются, и по умолчанию вызов Base.descendants возвращает пустой список! Я не уверен, если это связано с использованием JRuby или причуда о режиме Rails развития, или значение config.cache_classes, или что-то другое, но я был в состоянии решить эту проблему, делая это:

class Base 
    Descendant1.inspect 
    Descendant2.inspect 
    ... 

Да, это настоящая боль, но это позволяет вам работать с Rails, перезагружая ваши классы.

+0

Инициализация документа с использованием Base.new, как и выше, всегда будет создавать документ класса Base. Он не будет отвечать методам, характерным для базовых классов. Если вы проверите класс вновь созданного документа, это будет 'Base', а не' InheritedA'. – rubish

Смежные вопросы