rubymongoidmongoid3mongoid4

Mongoid nested embedded document save ignores query


I'm having trouble saving the correct nested embedded document with mongoid. I've tried this in both v3.1.6 and v4.0.0 and the result is the same. The parent document is saved, but the nested document I modified ignores the changes, and instead updates the first nested document instead.

Assume some models like so:

Mongoid.configure do |config|
  config.sessions = {default: {hosts: ["localhost:27017"], database: "test_mongoid"}}
end

class Band
  include Mongoid::Document

  field :name, type: String
  embeds_many :members
end

class Member
  include Mongoid::Document
  embedded_in :band

  field :name, type: String
  embeds_many :instruments
end

class Instrument
  include Mongoid::Document
  embedded_in :member

  field :name, type: String

  def make_badass!
    self.name = "Badass #{self.name}"
    self.save
  end
end

And a program that runs:

Band.destroy_all

a_band = {
  name: "The Beatles",
  members: [
    {
      name: 'Paul',
      instruments: [
        {
          name: 'Bass guitar'
        },
        {
          name: 'Voice'
        }
      ]
    }
  ]
}
Band.create(a_band)


the_beatles = Band.first

puts the_beatles.as_document

paul = the_beatles.members.first
voice = paul.instruments.where({name: "Voice"}).first

voice.make_badass!

puts Band.first.as_json

The database should now contain:

{
    "_id": ObjectId('53aa7d966d6172889c000000'),
    "name" : "The Beatles",
    "members" : [
        {
            "_id" : ObjectId('53aa7d966d6172889c010000'),
            "name" : "Paul",
            "instruments" : [
                {"_id" : ObjectId('53aa7d966d6172889c020000'), "name" : "Bass guitar"},
                {"_id" : ObjectId('53aa7d966d6172889c030000'), "name" : "Voice"}
            ]
        }
    ]
}

But instead, it contains:

{
    "_id": ObjectId('53aa7d966d6172889c000000'),
    "name" : "The Beatles",
    "members" : [
        {
            "_id" : ObjectId('53aa7d966d6172889c010000'),
            "name" : "Paul",
            "instruments" : [
                {"_id" : ObjectId('53aa7d966d6172889c020000'), "name" : "Badass Voice"},
                {"_id" : ObjectId('53aa7d966d6172889c030000'), "name" : "Voice"}
            ]
        }
    ]
}

What would be a working way of having the correct embedded document to change from within the instance method of Instrument?

Thanks for your help!


Solution

  • Mongoid is quickly forcing me to become an alcoholic. Hopefully it will help someone in the same situation.

    class Instrument
      include Mongoid::Document
      embedded_in :member
    
      field :name, type: String
    
      def make_badass
        self.name = "Badass #{self.name}"
        self.member.band.save
      end
    
      def unset_name
        # self.unset :name does not work
        self.remove_attribute :name
        self.member.band.save
      end
    
    end