Mongoid embeds_many: push document without save in order to preserve dirty state

橙三吉。 提交于 2019-12-10 15:03:15

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!