The following Bookshelf model hashes the users password when the model is saved, the only problem is that if I change that model.set()
call to a model.save()
it goes into an infinite save/changed loop.
var User = bookshelf.Model.extend({
tableName: 'users',
hasTimestamps: true,
constructor: function() {
var self = this;
bookshelf.Model.apply(this, arguments);
this.on('saving', function(model) {
if(!model.get('password')) {
return self.hashPassword(model);
}
});
},
hashPassword: function(model) {
bcrypt.genSalt(10, function(error, salt) {
bcrypt.hash(model.attributes.password, salt, function(error, hash) {
model.set({password: hash});
console.log(model.attributes);
});
});
}
});
I know that Backbone has a silent: true
option you can pass so that save()
doesn't trigger a changed event but I don't think Bookshelf supports it.
How can I save the changes model.set()
has made without causing a save/changed loop?
So it turns out that the model is saving before the hash_password method has returned a value, so I promiseified the bcrypt code like so:
hashPassword: function(password) {
return new Promise(function(resolve, reject) {
bcrypt.genSalt(10, function(error, salt) {
if(error) return reject(error);
bcrypt.hash(password, salt, function(error, hash) {
if(error) return reject(error);
return resolve(hash);
});
});
});
}
and completely refactored the model's constructor to use it:
constructor: function() {
var self = this;
bookshelf.Model.apply(this, arguments);
this.on('saving', function(model) {
if(!model.attributes.password) {
delete model.attributes.password;
} else {
return self.hashPassword(model.attributes.password)
.then(function(hash) {
model.set({ password: hash });
});
}
});
}
Hope this helps somebody :-)