-
Type: Bug
-
Resolution: Done
-
Priority: Major - P3
-
Affects Version/s: 6.0.3
-
Component/s: None
-
None
-
Environment:Rails 5.0.1
When the parent model specifies a "store_in client:" for a model which contains an embedded model, if you attempt to do an update_attributes on the embedded model it will attempt to save the data to the default db client and not the client associated with the parent.
Tracing through it could be something within the new persistence_context module introduced in 6.0.0 though thats as far as I was able to get.
Here is a simple setup to reproduce:
First the database configuration with multiple clients:
development: clients: default: database: dummy_development hosts: - localhost:27017 options: ecommerce: database: ecommerce-dummy-development hosts: - localhost:27017 options:
Parent And Embedded Models
module Testing class Order include Mongoid::Document store_in client: "ecommerce" store_in collection: 'testing_orders' field :uuid embeds_one :billing_address, :class_name => 'Testing::Address' end end module Testing class Address include Mongoid::Document field :name field :address_one embedded_in :order, :class_name => 'Testing::Order' end end
Test Scenario
Loading development environment (Rails 5.0.1) 2.3.3 :001 > order = Testing::Order.create!(:billing_address => {:address_one => "101 First Street"}) => #<Testing::Order _id: 58a8b8a11df32d30161114a0, uuid: nil> 2.3.3 :002 > order.reload.billing_address.address_one => "101 First Street" 2.3.3 :003 > order.billing_address.update_attributes({:address_one => "201 Second Street"}) => true 2.3.3 :004 > order.reload.billing_address.address_one => "101 First Street" 2.3.3 :005 > order.billing_address.address_one = "303 3rd street" => "303 3rd street" 2.3.3 :006 > order.save! => true 2.3.3 :007 > order.reload.billing_address.address_one => "303 3rd street"
Here are the relevant mongo logs for each operation.
Initial Create, saves appropriately on ecommerce-dummy-development
7-02-18T13:03:52.725-0800 D COMMAND [conn6] run command ecommerce-dummy-development.$cmd { insert: "testing_orders", documents: [ { _id: ObjectId('58a8b6b81df32d2d50ed37f4'), billing_address: { _id: ObjectId('58a8b6b81df32d2d50ed37f5'), address_one: "101 First Street" } } ], ordered: true }
update via update_attributes.
Notice it attemps to save on dummy_development and not ecommerce-dummy-development as well as fails to save yet the method returns true.
2017-02-18T13:06:54.807-0800 D COMMAND [conn9] run command dummy_development.$cmd { update: "testing_orders", updates: [ { q: { _id: ObjectId('58a8b6b81df32d2d50ed37f4'), billing_address._id: ObjectId('58a8b6b81df32d2d50ed37f5') }, u: { $set: { billing_address.address_one: "201 Second Street" } }, multi: false, upsert: false } ], ordered: true } 2017-02-18T13:06:54.807-0800 D QUERY [conn9] Collection dummy_development.testing_orders does not exist. Using EOF plan: query: { _id: ObjectId('58a8b6b81df32d2d50ed37f4'), billing_address._id: ObjectId('58a8b6b81df32d2d50ed37f5') } sort: {} projection: {} 2017-02-18T13:06:54.807-0800 I WRITE [conn9] update dummy_development.testing_orders query: { _id: ObjectId('58a8b6b81df32d2d50ed37f4'), billing_address._id: ObjectId('58a8b6b81df32d2d50ed37f5') } planSummary: EOF update: { $set: { billing_address.address_one: "201 Second Street" } } keysExamined:0 docsExamined:0 nMatched:0 nModified:0 numYields:0 loc
update field directly
2017-02-18T13:13:26.713-0800 D QUERY [conn12] Using idhack: { _id: ObjectId('58a8b8a11df32d30161114a0') } 2017-02-18T13:13:26.713-0800 I WRITE [conn12] update ecommerce-dummy-development.testing_orders query: { _id: ObjectId('58a8b8a11df32d30161114a0') } planSummary: IDHACK update: { $set: { billing_address.address_one: "303 3rd street" } } keysExamined:1 docsExamined:1 nMatched:1 nModified:1 numYields:0 locks:{ Global: { acquireCount: { r: 1, w: 1 } }, Database: { acquireCount: { w: 1 } }, Collection: { acquireCount: { w: 1 } } } 0ms
Its this line here in persistence_context.rb that ultimately pulls the wrong client connection during the update operation. We have yet to try and debug this even further to see why this might be the case.
def collection(parent = nil) name = parent ? parent.collection_name : collection_name client[name.to_sym] end
It certainly could be something we're missing in our configuration so we've tried to dumb it down to the simplest example that you see above. The code works as expected in all previous versions of mongoid except for the 6.0.x versions.