Home > Software design >  Go GORM - BeforeUpdate fields have old values
Go GORM - BeforeUpdate fields have old values

Time:09-01

I have a Go application with GORM and I'm trying to hash Users' password fields every time they are updated.

To achieve this I'm using the BeforeUpdate hook provided by GORM. The problem that I'm facing is that on the said hook the Password field for the user (u.password) has the old hashed password value that is already stored on the DB instead of the newPassword value that I'm updating it with. So when I hash the password on the hook, I'm really just hashing the the already hashed old password.

My BeforeUpdate hook:

func (u *User) BeforeUpdate(tx *gorm.DB) (err error) {
  if (tx.Statement.Changed("Password")) {
    bytePassword := []byte(u.Password) // Old password value here!
    passwordHash, err := bcrypt.GenerateFromPassword(bytePassword, bcrypt.DefaultCost)
    if (err != nil) { return err }
    tx.Statement.SetColumn("password", string(passwordHash))
  }
  return nil
}

And the update is triggered like this:

var user models.User
err := db.First(&user, id).Error
if (err != nil) { log.Fatal(err) }
// Not sure how to access this "newPassword" value on the "BeforeUpdate" hook
err = db.Model(&user).Update("password", newPassword).Error
if (err != nil) { log.Fatal(err) }

Edit: Working solution thanks to @s3vt's answer

Just had to change my BeforeUpdate hook:

func (u *User) BeforeUpdate(tx *gorm.DB) (err error) {
  if (tx.Statement.Changed("Password")) {
    u.Password = tx.Statement.Dest.(map[string]interface{})["password"].(string)
    bytePassword := []byte(u.Password)
    passwordHash, err := bcrypt.GenerateFromPassword(bytePassword, bcrypt.DefaultCost)
    if (err != nil) { return err }
    tx.Statement.SetColumn("password", string(passwordHash))
  }
  return nil
}

CodePudding user response:

You can get the new password value form the tx.Statement.Dest map. This is the same map that SetColumn updates the value to.

OR set the new password value before the actual update call.

user.Password = newPassword
err = db.Model(&user).Updates(&user).Error

In this case old password will not be available at the hook.

  • Related