Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ability to register functions to run before saving to database #252

Closed
cultofmetatron opened this issue Feb 25, 2014 · 3 comments
Labels

Comments

@cultofmetatron
Copy link

@cultofmetatron cultofmetatron commented Feb 25, 2014

Ok so I know there's the 'saving' event that fires off before the save happens.

However, I want to be able to have several asynchronous functions run before the save actually runs. Think preprocessing on models. One example would be using bcrypt to generate a salt and hash for a model before saving since I don't store the password on the database. Currently, the way I've done this is to overide save.

save: function() {
    return Promise.all([
      this.buildSalt()
    ])
    .bind(this)
    .then(function() {
      return db.Model.prototype.save.call(this);
    });
  },

I'd like to instead have an attribute 'beforeSave'(I'm not picky about what to call it) of functions or strings resolvable to the current instance's methods that would return promises where all of them must resolve before the save runs.

var User = db.Model.extend({
  beforeSave: [
    'buildSalt'
  ],
})

anotther idea I had for more fine grained control would be a function that
itself would return a promise that must resolve before save executes. This might be
more flexible.

the default could then be as simple as

var User = db.Model.extend({
  beforeSave: function() {
    return Promise.resolve();
  },
})

then the example above could be as simple as

var User = db.Model.extend({
  beforeSave: function() {
    return Promise.all([
      this.buildSalt()
    ]);
  },
  buildSalt: function() {
    if (this.get('password')) { return this.generatePasswordHash(); }
    return Promise.resolve().bind(this);
  },
  //generates a promise which is resolved when the user's salt is generated
  getSalt: function() {
    return this.generateSalt().bind(this).then(function(salt) {
      this.set('salt', this.get('salt') || salt);
      return this.get('salt');
    });
  },
  //returns a promise for the salt
  generateSalt: function() {
    return bcrypt.genSaltAsync(8);
  },
  //returns a promise for the password hash
  generatePasswordHash: function() {
    return this.getSalt()
      .bind(this)
      .then(function(salt) {
        return bcrypt.hashAsync(this.get('password'), salt, null);
      })
      .then(function(hash) {
        this.set('password_hash', hash);
        this.unset('password');
        return this;
      });
  },

})

I'd be happy to implement this and submit a pull request if you guys there is enough interest.

@tgriesser

This comment has been minimized.

Copy link
Member

@tgriesser tgriesser commented Feb 25, 2014

So you should actually be able to do this with events...

var User = Model.extend({
   initialize: function() {
      this.on('saving', this.beforeSave);
   }
});

Any of the lifecycle events are actually using trigger-then a promise-aware events implementation such that it waits if a promise is returned in any of the event handlers, and rejects the saving action if an error is thrown or a rejected promise is returned in any handler.

Let me know if this sounds good for what you're looking for.

@tgriesser tgriesser added the question label Feb 25, 2014
@cultofmetatron

This comment has been minimized.

Copy link
Author

@cultofmetatron cultofmetatron commented Feb 25, 2014

wow sounds like it, looks like its time for a refactor tommorrow. Thx for letting me know

@light24bulbs

This comment has been minimized.

Copy link

@light24bulbs light24bulbs commented Feb 4, 2015

Wow, thats cool! Is that mentioned in the relevant section of the docs? It's an extremely common use case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
4 participants
You can’t perform that action at this time.