Uploaded image for project: 'Mongoid'
  1. Mongoid
  2. MONGOID-4415

Storage options of parent are not used for embedded document when persisting

    • Type: Icon: Bug Bug
    • Resolution: Done
    • Priority: Icon: Major - P3 Major - P3
    • 6.1.1
    • 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:

      mongoid.yml
      development:
        clients:
          default:
            database: dummy_development
            hosts:
              - localhost:27017
            options:
          ecommerce:
            database: ecommerce-dummy-development
            hosts:
              - localhost:27017
            options:
      

      Parent And Embedded Models

      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.

            Assignee:
            emily.stolfo Emily Stolfo
            Reporter:
            cdiebner Chris
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: