I have a userSchema
that looks like this:
var userSchema = new Schema({
name: {
type: String
, required: true
, validate: [val
I eventually discovered that you can use a combination of virtual paths and the invalidate
function to achieve this, as shown in this gist, for the very same purpose of matching passwords: https://gist.github.com/1350041
To quote directly:
CustomerSchema.virtual('password')
.get(function() {
return this._password;
})
.set(function(value) {
this._password = value;
var salt = bcrypt.gen_salt_sync(12);
this.passwordHash = bcrypt.encrypt_sync(value, salt);
});
CustomerSchema.virtual('passwordConfirmation')
.get(function() {
return this._passwordConfirmation;
})
.set(function(value) {
this._passwordConfirmation = value;
});
CustomerSchema.path('passwordHash').validate(function(v) {
if (this._password || this._passwordConfirmation) {
if (!val.check(this._password).min(6)) {
this.invalidate('password', 'must be at least 6 characters.');
}
if (this._password !== this._passwordConfirmation) {
this.invalidate('passwordConfirmation', 'must match confirmation.');
}
}
if (this.isNew && !this._password) {
this.invalidate('password', 'required');
}
}, null);
I know the thread is old but if it could save someone's time... My approach uses pre-validate hook and works perfectly for me
schema.virtual('passwordConfirmation')
.get(function() {
return this._passwordConfirmation;
})
.set(function(value) {
this._passwordConfirmation = value;
});
schema.pre('validate', function(next) {
if (this.password !== this.passwordConfirmation) {
this.invalidate('passwordConfirmation', 'enter the same password');
}
next();
});
I think password matching belongs in the client interface and should never get to the server (DB layer is already too much). It's better for the user experience not to have a server roundtrip just to tell the user that 2 strings are different.
As for thin controller, fat model... all these silver bullets out there should be shot back at the originator. No solution is good in any situation. Think everyone of them in their own context.
Bringing the fat model idea here, makes you use a feature (schema validation) for a totally different purpose (password matching) and makes your app dependent on the tech you're using now. One day you'll want to change tech and you'll get to something without schema validation at all... and then you'll have to remember that part of functionality of your app relied on that. And you'll have to move it back to the client side or to the controller.
The second verification password doesn't need to be submitted for registration. You could probably get away with validating the two fields are equal on the client-side.
It's kind of late but for the sake of people having similar issues. i ran into a similar problem lately, and here was how i went about it; i used a library called joi
const joi = require('joi');
...
function validateUser(user){
const schema = joi.object({
username: joi.string().min(3).max(50).required(),
email: joi.string().min(10).max(255).required().email(),
password: joi.string().min(5).max(255).required(),
password2: joi.string().valid(joi.ref('password')).required(),
});
return schema.validate(user);
}
exports.validate = validateUser;
I use express-validator before it ever gets down to the schema level in ./routes/signup.js:
exports.post = function(req, res){
req.assert('email', 'Enter email').notEmpty().isEmail();
req.assert('username', 'Enter username').notEmpty().isAlphanumeric().len(3,20);
req.assert('password', 'Enter password').notEmpty().notContains(' ').len(5,20);
res.locals.err = req.validationErrors(true);
if ( res.locals.err ) {
res.render('signup', { message: { error: 'Woops, looks like we need more info...'} });
return;
}
...//save
};