22

I defined my hook beforeCreate as following:

module.exports = function (sequelize, DataTypes) {
  var userSchema = sequelize.define('User', {
  // define...
  });
  userSchema.beforeCreate(function (model) {
    debug('Info: ' + 'Storing the password');    
    model.generateHash(model.password, function (err, encrypted) {
      debug('Info: ' + 'getting ' + encrypted);

      model.password = encrypted;
      debug('Info: ' + 'password now is: ' + model.password);
      // done;
    });
  });
};

and when I create a the model

  User.create({
    name:           req.body.name.trim(),
    email:          req.body.email.toLowerCase(),
    password:       req.body.password,
    verifyToken:    verifyToken,
    verified:       verified
  }).then(function (user) {
    debug('Info: ' + 'after, the password is ' + user.password);    
  }).catch(function (err) {
    // catch something
  });

Now what I get from this is

Info: Storing the password +6ms
Info: hashing password 123123 +0ms    // debug info calling generateHash()
Executing (default): INSERT INTO "Users" ("id","email","password","name","verified","verifyToken","updatedAt","createdAt") VALUES (DEFAULT,'wwx@test.com','123123','wwx',true,NULL,'2015-07-15 09:55:59.537 +00:00','2015-07-15 09:55:59.537 +00:00') RETURNING *;

Info: getting $2a$10$6jJMvvevCvRDp5E7wK9MNuSRKjFpieGnO2WrETMFBKXm9p4Tz6VC. +0ms
Info: password now is: $2a$10$6jJMvvevCvRDp5E7wK9MNuSRKjFpieGnO2WrETMFBKXm9p4Tz6VC. +0ms
Info: after, the password is 123123 +3ms

It seems that every part of the code is working. Creating a user schema will invoke beforeCreate, which properly generates the hash code for the password.... except it didn't write to the database!

I'm certain that I'm missing a very important and OBVIOUS piece of code, but I just can't find where the problem is (aghh). Any help appreciated!

Alon
  • 357
  • 1
  • 2
  • 9

2 Answers2

39

Hooks are called in an asynchronous fashion in Sequelize, so you need to call the completion callback when you're done:

userSchema.beforeCreate(function(model, options, cb) {
  debug('Info: ' + 'Storing the password');    
  model.generateHash(model.password, function(err, encrypted) {
    if (err) return cb(err);
    debug('Info: ' + 'getting ' + encrypted);

    model.password = encrypted;
    debug('Info: ' + 'password now is: ' + model.password);
    return cb(null, options);
  });
});

(alternatively, you can return a promise from the hook)

robertklep
  • 198,204
  • 35
  • 394
  • 381
20

For newer versions of Sequelize, the hooks no longer have callback functions but promisses. Therefor the code would look more like the following:

userSchema.beforeCreate(function(model, options) {
    debug('Info: ' + 'Storing the password');

    return new Promise ((resolve, reject) => {
        model.generateHash(model.password, function(err, encrypted) {
            if (err) return reject(err);
            debug('Info: ' + 'getting ' + encrypted);

            model.password = encrypted;
            debug('Info: ' + 'password now is: ' + model.password);
            return resolve(model, options);
        });
    });
});
Rene
  • 466
  • 5
  • 12
  • Does sequelize support async/await functions in the model hooks? – Jadex1 Jan 01 '18 at 18:47
  • Async/await functions arent implemented in node yet, so when you write Async/Await it is transpiled back to promises by Babel – Rene Jan 01 '18 at 18:51
  • I thought async/await was released with node 8 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function I don't use babel in my project, and my code compiles with the async/await functions. Could you explain please? – Jadex1 Jan 01 '18 at 18:59
  • Oh i guess you're right, but the release notes say that async await uses promises so it should still be fine – Rene Jan 01 '18 at 19:06