Reputation: 149
I am trying to has a password on my user model but never seeing before create being called.
Using Express 4.2 and waterline 0.10.14.
User Model:
var Waterline = require('waterline'),
uuid = require('uuid'),
bcrypt = require('bcrypt');
var User = module.exports = Waterline.Collection.extend({
identity: 'user',
connection: 'default',
autoPK: false, // prevents creation of the id
schema: true,
types: {
// Custom Validation - https://github.com/balderdashy/waterline-docs/blob/master/models.md#custom-validations
},
attributes: {
uuid: {
type: 'uuidv4',
primaryKey: true,
defaultsTo: uuid.v4
},
first_name: {
type: 'string',
required: true
},
last_name: {
type: 'string',
required: true
},
email: {
type: 'email',
required: true,
unique: true
},
username: {
// TODO: validate no spaces, or special characters
type: 'string',
required: true,
unique: true,
index: true,
minLength: 3,
maxLength: 30
},
password: {
// TODO: add rules on password
type: 'string',
minLength: 6,
maxLength: 50,
required: true,
columnName: 'encrypted_password'
},
// TODO: custom input with - https://developers.google.com/places/documentation/autocomplete#place_autocomplete_requests
location: {
type: 'string'
},
activated: {
type: 'boolean',
defaultsTo: false
},
activationToken: {
type: 'string'
},
// Override toJSON instance method to remove values
toJSON: function() {
var obj = this.toObject();
// delete obj.password;
delete obj.email;
delete obj.activated;
delete obj.activationToken;
return obj;
},
verifyPassword: function (password) {
return bcrypt.compareSync(password, this.password);
},
changePassword: function(newPassword, next){
this.password = newPassword;
this.save(function(err, u) {
return next(err,u);
});
},
// Lifecycle Callbacks
beforeCreate: function(attrs, next) {
console.log('beforeCreate - user');
bcrypt.genSalt(process.env.SALT_WORK_FACTOR, function(err, salt) {
if (err) return next(err);
bcrypt.hash(attrs.password, salt, function(err, crypted) {
if(err) return next(err);
attrs.password = crypted;
attrs.activationToken = crypto.token(new Date().getTime() + attrs.email);
return next();
});
});
},
beforeUpdate: function (attrs, next) {
if(attrs.newPassword){
bcrypt.genSalt(process.env.SALT_WORK_FACTOR, function(err, salt) {
if (err) return next(err);
bcrypt.hash(attrs.newPassword, salt, function(err, crypted) {
if(err) return next(err);
delete attrs.newPassword;
attrs.password = crypted;
return next();
});
});
}
else {
return next();
}
}
}
});
This is how its being called on my controller.
exports.create = function (req, res, next) {
app.models.user.create(req.body, function (err, model) {
if(err) return res.error('users/signup', err);
res.success('users/welcome', model);
});
};
I never see the log on my beforeCreate called and the password is never hashed. Thoughts?
Edit: User model to reflect most recent changes. Also noticed beforeCreate should run before validations.
Upvotes: 1
Views: 448
Reputation: 149
This was a small mistake on my end having the lifecycle callbacks wrapped up in the same object as my attributes. They have to be outside of that object.
Upvotes: 1
Reputation: 595
I think I know why your beforeCreate is not running. It is because password is a required field. Waterline actually runs the validate callback before running the beforeCreate callback. Since password doesn't exist until values.password is created the validation fails and beforeCreate never gets called. I'm assuming that you're just passing a newPassword parameter when you're creating a new user.
Upvotes: 1