1

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?

Pablo Pazos
  • 3,080
  • 29
  • 42
  • See Graeme's answer at https://github.com/grails/grails-data-mapping/issues/961#issuecomment-309379214. – Jeff Scott Brown Oct 21 '19 at 13:31
  • Is that I'm missing the dirty checks because I use my own setters? – Pablo Pazos Oct 21 '19 at 15:22
  • 1
    "Is that I'm missing the dirty checks because I use my own setters?" - Not really. The issue is that your setter (`setPasswordToken`) is doing field access with `this.resetPasswordToken = (java.util.UUID.randomUUID() as String)`. If that were `setResetPasswordToken((java.util.UUID.randomUUID() as String))`, I expect it to work. because the dirty checking is inside the `setResetPasswordToken` method, which you aren't using. – Jeff Scott Brown Oct 21 '19 at 16:22
  • That is what I meant with "missing the dirty check", by not using the setResetPasswordToken method, the dirty bit is not set for the field. I got it now. – Pablo Pazos Oct 21 '19 at 16:51
  • 1
    Great! Glad I could help. – Jeff Scott Brown Oct 21 '19 at 17:11
  • 1
    not related but if you change your `setPasswordToken` method name to a more specific as `renewThePasswordToken` you can avoid to declare the transients – Jorge Aguilera Gonzalez Oct 22 '19 at 06:49

1 Answers1

3

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.

Jeff Scott Brown
  • 26,804
  • 2
  • 30
  • 47