-
Type: Bug
-
Resolution: Won't Do
-
Priority: Major - P3
-
None
-
Affects Version/s: None
-
Component/s: Associations, Callbacks
-
None
Minimal Rails app with a test case available here: https://github.com/mbell697/mongoid_update_on_find
It appears that setting an embedded relation in an after_initialize callback causes an update to occur, using the models from the linked example:
ParentDoc.create name: "parent_test", embedded_doc: EmbeddedDoc.new(name: 'test_child', child_field: 'test_child_field')
`
MOPED: 127.0.0.1:27017 COMMAND database=admin command={:ismaster=>1} (0.9210ms) MOPED: 127.0.0.1:27017 INSERT database=mongoid_update_on_find_development collection=parent_docs documents=[{"_id"=>"54d42bbdc607b8314f000001", "name"=>"parent_test", "updated_at"=>2015-02-06 02:49:33 UTC, "created_at"=>2015-02-06 02:49:33 UTC, "embedded_doc"=>{"_id"=>"54d42bbdc607b8314f000002", "name"=>"test_child", "child_field"=>"test_child_field"}}] flags=[] (0.1500ms)
`
ParentDoc.where(name: 'parent_test').only(:name).first
`
MOPED: 127.0.0.1:27017 QUERY database=mongoid_update_on_find_development collection=parent_docs selector={"$query"=>{"name"=>"parent_test"}, "$orderby"=>{:_id=>1}} flags=[:slave_ok] limit=-1 skip=0 batch_size=nil fields={"name"=>1} (0.9749ms) MOPED: 127.0.0.1:27017 UPDATE database=mongoid_update_on_find_development collection=parent_docs selector={"_id"=>"54d42bbdc607b8314f000001"} update={"$set"=>{"embedded_doc"=>{"_id"=>"54d42bebc607b8314f000003", "name"=>"default", "child_field"=>"default", "updated_at"=>2015-02-06 02:50:19 UTC, "created_at"=>2015-02-06 02:50:19 UTC}}} flags=[] (0.1249ms)
`
I'm using .only() as an easy way to trigger the problem by causing the conditional in the after_initialize callback to pass.
I think this is a pretty nasty bug, I ran into it by using what should have been a read only query with all.only() that actually ended up replacing every embedded doc in a collection, similar to the example case.
Is there a better way to manage defaults for embedded objects that is safe when used with features like only? I could used autobuild with a before_validation callback to ensure the embedded doc is set, however in reality I need more than a default call to new on the embedded_doc to setup the defaults.