问题
In Mongoid, pushing a document into an embeds_many
relation automatically persists the document to the database. Normally, this is fine, but I run into problems when I need to track changes to the embedded document.
Say you have two models:
class List
include Mongoid::Document
embeds_many :items
field :title
end
class Item
include Mongoid::Document
embedded_in :list
field :name
end
This happens to the .changes attribute:
list = List.new(title: 'List title')
list.save #list is now persisted
item = Item.new(name: 'Item name')
item.changes #returns Hash with {'name' => [nil, 'Item name']}
list.items << item #saves item to database under the hood
item.changes #returns empty Hash, because item was autosaved with list
I could use item.previous_changes
to inspect the changes that were made before pushing the item into the list, but in my specific case, this would give me all kinds of troubles to keep things manageable.
What I would like to achieve, is to be able to initialize an Item
document and then add it to list
(via <<
or push
) without persisting it immediately.
I'm aware that Mongoid does provide an option to set up embeds_many
relations without persisting (see http://mongoid.org/en/mongoid/docs/relations.html#embeds_many):
list.items.build(name: 'Another item')
The problem there is that Mongoid creates the Item instance for you. In my case, the documents in the embeds_many
relation may be subclasses of Item (e.g. SpecialItem < Item
), which wouldn't work well with build
. But if anyone knows of a way to get around this limitation, I'd also be happy to accept it as an answer.
回答1:
To follow up on the "building a subclass" issue using your example, you can:
list.items.build({
name: "Another Item"
}, SpecialItem)
To specify the (sub)class that you want Mongoid to build for you.
回答2:
To answer my own question: the problem is solved by assigning the parent document to the child, instead of adding the child to the list or children.
Continuing on the example above, you should do
item.list = list #no database query
instead of
list.items << item #automatic database insert
to set the parent - child reference without autosaving anything to the database.
来源:https://stackoverflow.com/questions/15521691/mongoid-embeds-many-push-document-without-save-in-order-to-preserve-dirty-state