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

embeds_many seems to be too persitend

    • Type: Icon: Task Task
    • Resolution: Done
    • 2.3.0
    • Affects Version/s: None
    • Component/s: None

      I ran in a problem, which is related to MONGOID-1143 + MONGOID-768 and the changes made in 2.2.0 to fix them.

      I have the following test:

      it "should update a users role on PUT" do
        user = Factory.create(:admin, :user_roles => ['user'])
        User.find(user.id).user_roles.should eq ['user']
        put :update, :id => user.id, :user => { :user_roles => ['admin'] }
        response.should be_redirect
        User.find(user.id).user_roles.should eq ['admin']
      end
      

      and my User and Role Class look like this:

      class User
        include Mongoid::Document
        
        embeds_many :roles
        
        def user_roles=(new_roles)
          self.roles = new_roles.collect { |role_name| Role.new(:name => role_name) unless role_name.blank? }
        end
        
        def user_roles
          roles.map { |r| r.name }
        end
        
      end
      
      class Role
        include Mongoid::Document
      
        field :name, :type => String
      
        embedded_in :user  
      end
      

      When i run the test i get

           Failure/Error: User.find(user.id).user_roles.should eq ['admin']
             
             expected ["admin"]
                  got ["user", "admin"]
      

      and the logs show this line:

      MONGODB crowdmedia_pages_test['users'].update({"_id"=>BSON::ObjectId('4e65fbb08095296386000022')}, {"$pushAll"=>{"roles"=>[{"name"=>"admin", "_id"=>BSON::ObjectId('4e65fbb08095296386000025')}]}})
      

      i checked the mongodb docs and lerned that a pushAll appends the array to the field, so i modified my code:

      def user_roles=(new_roles)
        self.roles = []
        self.roles = new_roles.collect { |role_name| Role.new(:name => role_name) unless role_name.blank? }
      end
      
      # test results in:
      Failure/Error: User.find(user.id).user_roles.should eq ['admin']
        
        expected ["admin"]
             got ["user"]
      
      # log shows:
      MONGODB crowdmedia_pages_test['users'].update({"_id"=>BSON::ObjectId('4e65fd3a809529645d000022')}, {"$unset"=>{"roles"=>true}, "$pushAll"=>{"roles"=>[{"name"=>"admin", "_id"=>BSON::ObjectId('4e65fd3a809529645d000025')}]}})
      

      looks like none of these changes got saved...

      what solved the problem is:

      def user_roles=(new_roles)
        self.roles = []
        self.save
        self.roles = new_roles.collect { |role_name| Role.new(:name => role_name) unless role_name.blank? }
      end
      
      # logs:
      MONGODB crowdmedia_pages_test['users'].update({"_id"=>BSON::ObjectId('4e65fded80952964b8000022')}, {"$unset"=>{"roles"=>true}})
      MONGODB crowdmedia_pages_test['$cmd'].find({"count"=>"users", "query"=>{:email=>/^johnnie23@email\.com$/i, :_id=>{"$ne"=>BSON::ObjectId('4e65fded80952964b8000022')}}, "fields"=>nil})
      MONGODB crowdmedia_pages_test['users'].update({"_id"=>BSON::ObjectId('4e65fded80952964b8000022')}, {"$pushAll"=>{"roles"=>[{"name"=>"admin", "_id"=>BSON::ObjectId('4e65fded80952964b8000025')}]}})
      

      now my tests are passing but it feels strange to put a self.save in a method which get triggered by an update_attributes call to save the model... and i got an additional query to the db

      am i missing something or is it a bug in mongoid?

      would be great to get some feedback to this issue!

      cc tobsch

            Assignee:
            Unassigned Unassigned
            Reporter:
            fsmanuel fsmanuel
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved: