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

after_initialize causes problems with changing/saving of embeded documents

    • Type: Icon: Task Task
    • Resolution: Done
    • Priority: Icon: Blocker - P1 Blocker - P1
    • 5.0.1
    • Affects Version/s: None
    • Component/s: None
    • None

      Greetings,

      Using mongoid(git:38de2e96edc8f64fbe3cdbe062f1d91e9feb388d 2 days ago) I encountered a perplexing problem when trying to save embedded documents. I believe after_initialize prevents the saving of embedded documents. I have the test files located in a git repo for your convenience:

      https://github.com/danlo/mongoid_after_init_bug

      test.rb

      require 'mongoid'
      require 'pp'
      
      Mongoid.load!('mongoid.yml', :test)
      
      # the big container object
      class Book
        include Mongoid::Document
        embeds_many :pages
      end
      
      # the smaller embeded_in object
      class Page
        include Mongoid::Document
        embedded_in :book
        embeds_many :notes
        field :content, :type => String
      end
      
      # and one more time
      class Note
        include Mongoid::Document
        embedded_in :page
        field :message, :type => String
      end
      
      # clear previous test cases
      Book.mongo_session[Book.collection.name].drop
      
      # setup the basic object
      
      book = Book.new({
        :pages => [
          {
            content: "Page 1", 
            notes: [ 
              { message: "Page 1 / Note A" },
              { message: "Page 1 / Note B" }
            ]
          },
          {
            content: "Page 2", 
            notes: [ 
              { message: "Page 2 / Note A" },
              { message: "Page 2 / Note B" }
            ]
          }
        ]
      })
      book.id = '123'
      book.save
      
      puts "---------------- A good copy of the document"
      pp book.as_document
      

      test2.rb

      require 'mongoid'
      require 'pp'
      require 'byebug'
      require 'pry-byebug'
      
      Mongoid.load!('mongoid.yml', :test)
      
      # the big container object
      class Book
        include Mongoid::Document
        embeds_many :pages
      end
      
      # the smaller embeded_in object
      class Page
        include Mongoid::Document
        embedded_in :book
        embeds_many :notes
        field :text, :type => String
      
        if true # true, breaks the code; false, allows the code to work.
          after_initialize do
            if self[:content]
              self[:text] = self[:content]
              self.remove_attribute(:content)
            end
          end
        end
      end
      
      class Note
        include Mongoid::Document
        embedded_in :page
        field :message, :type => String
      end
      
      book = Book.find '123'
      # we will now remove those notes, and a new "C" note
      book.pages.each do | page | 
        # going to make sure we actually clear it
        page.notes.clear
        page.notes = nil
        page.notes.destroy_all
        page.save
        page.notes.new(message: "Note C")
        page.save
      end
      
      if ! book.save
         puts "-------------- Oh noes! We didn't save"
      end
      
      puts "---------------- We have removed all notes from all pages; and added a new 'Note C'; Below is correct"
      pp book.as_document
      
      puts "\n\n---------------- Now reloading the book we see that 'Note C' was never saved"
      book = Book.find '123'
      pp book.as_document
      

      sample output

      $ bundle exec ruby test.rb
      ---------------- A good copy of the document
      {"_id"=>"123",
       "pages"=>
        [{"_id"=>"525e0b789f4a1a800c000001",
          "content"=>"Page 1",
          "notes"=>
           [{"_id"=>"525e0b789f4a1a800c000002", "message"=>"Page 1 / Note A"},
            {"_id"=>"525e0b789f4a1a800c000003", "message"=>"Page 1 / Note B"}]},
         {"_id"=>"525e0b789f4a1a800c000004",
          "content"=>"Page 2",
          "notes"=>
           [{"_id"=>"525e0b789f4a1a800c000005", "message"=>"Page 2 / Note A"},
            {"_id"=>"525e0b789f4a1a800c000006", "message"=>"Page 2 / Note B"}]}]}
      $ bundle exec ruby test2.rb
      ---------------- We have removed all notes from all pages; and added a new 'Note C'; Below is correct
      {"_id"=>"123",
       "pages"=>
        [{"_id"=>"525e0b789f4a1a800c000001",
          "notes"=>[{"_id"=>"525e0b7b9f4a1aec2c000001", "message"=>"Note C"}],
          "text"=>"Page 1"},
         {"_id"=>"525e0b789f4a1a800c000004",
          "notes"=>[{"_id"=>"525e0b7b9f4a1aec2c000002", "message"=>"Note C"}],
          "text"=>"Page 2"}]}
      
      
      ---------------- Now reloading the book we see that 'Note C' was never saved
      {"_id"=>"123",
       "pages"=>
        [{"_id"=>"525e0b789f4a1a800c000001",
          "notes"=>
           [{"_id"=>"525e0b789f4a1a800c000002", "message"=>"Page 1 / Note A"},
            {"_id"=>"525e0b789f4a1a800c000003", "message"=>"Page 1 / Note B"}],
          "text"=>"Page 1"},
         {"_id"=>"525e0b789f4a1a800c000004",
          "notes"=>
           [{"_id"=>"525e0b789f4a1a800c000005", "message"=>"Page 2 / Note A"},
            {"_id"=>"525e0b789f4a1a800c000006", "message"=>"Page 2 / Note B"}],
          "text"=>"Page 2"}]}
      $    
      

      Thank you for all the hard work you guys are putting into this. I can't wait until 4.0.0 comes out!

            Assignee:
            emily.stolfo Emily Stolfo
            Reporter:
            danlo danlo
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated:
              Resolved: