Search code examples
grailsgrails-3.3

Grails 3.3.10 value set in domain method is not being saved


I have a User class with a resetPasswordToken attribute, that is a UUID set when a user tries to reset his password.

On Grails 2.5.6 I had something like this that worked OK:

class UserController {


   def forgotPassword(String email)
   {
      ...
      def user = User.findByEmail(email)
      user.setPasswordToken()
      user.save(flush: true()
      ...
   }
}

class User {

   ...
   String resetPasswordToken

   static transients = ['passwordToken']

   def setPasswordToken()
   {
      ...
      this.resetPasswordToken = (java.util.UUID.randomUUID() as String)
   }
}

Now I migrated that to GRails 3.3.10 and the resetPasswordToken is NULL on the database after the forgotPassword action is invoked. If I do a println after the user.setPasswordToken() is invoked, I can see the resetPasswordToken is set to an UUID, but is not in the DB. Also checked for errors on the save, and there are no errors.

Strange thing, if I do user.resetPasswordToken = "xxxx" in the controller, the value is saved into the database correctly.

Not sure what is going on with the value set in the setPasswordToken() not being saved into the DB. Any pointers?


Solution

  • See the comment at https://github.com/grails/grails-data-mapping/issues/961#issuecomment-309379214. The issue you are experiencing is one of dirty checking, which changed in GORM 6.1.

    Consider this code...

    class Person {
        String name
        String email
    
        void updateName(String newName) {
            this.name = newName
        }
    
        static constraints = {
            email email: true
        }
    }
    

    That updateName method will not result in the name property being marked as dirty. The following code would result in the name property being marked as dirty:

    class Person {
        String name
        String email
    
        void updateName(String newName) {
            setName newName
        }
    
        static constraints = {
            email email: true
        }
    }
    

    If you really want to turn on the old way of dirty checking you can do that per the instructions in the comment I linked above but be aware of the performance penalty of doing so. The recommended approach would be to use the setter or to explicitly mark the property as dirty using the markDirty method.

    I hope that helps.