-
Notifications
You must be signed in to change notification settings - Fork 362
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
Implement before/after validation hook #545
Conversation
The order of execution for a valid model is as follows:
The order of execution for an invalid model is as follows:
|
I'll take a look at the code later. There is one thing I don't understand though: since you are creating the (temporary) files in a remote hook, why can't you clean it in a remote hook too?
|
@bajtos I seem to recall that This doesn't change the fact that I think such a hook would make a lot of sense, because it does not need to be run a remoting context, making this a much more robust solution. I believe it also remedies the disparity between the new operation hooks and the now deprecated |
TL;DR Instead of We should also provide a similar hook in strong-remoting, something like "afterRemoteError" - see strongloop/strong-remoting#189 Long version First of all, I want to make it clear that I understand that the current version may not be powerful enough to support the use cases that you (and @clarkorz in #433) and that I want to find a good solution that will work for you. IMO, the use-cases for before/after validation hooks I've seen so far are trying to use a wrong tool for the job. They are trying to work around a fact that the proper way is not available (yet). Let's take your example of cleaning up a (temporary) file upload. First of all, a valid model data does not imply that the database request will pass:
Therefore it's not enough to implement the cleanup in "after validate" hook, we need a more generic "save failed" hook. Secondly, remoting and operations hooks are not meant to be the only way of customising model methods. In many cases, it's better to write a single cohesive custom method rather than split the implementation across multiple hooks. MyModel.upload = function(data, req, cb) {
// 1. handle uploaded files (multipart/form-data)
// NOTE: this should be provided by strong-remoting OOTB
// https://github.com/strongloop/strong-remoting/issues/35
data.filepath = /* the file */;
MyModel.create(data, function(err, created) {
if (err) {
// remove the file
cb(err);
}
cb(null, created);
});
};
// optionally remove "MyModel.create" from REST API
// an map "MyModel.upload" as "POST /MyModels" You can object that you need this behaviour for multiple methods (create, update), which is a valid argument. However, I still believe it's a bad idea implement this feature using a mix of hooks from different abstraction levels (remoting, operations).
I see. Let's fix the problem in strong-remoting then, don't add new stuff to LoopBack only because we need a workaround for a missing feature of strong-remoting. strongloop/strong-remoting#189
I agree we should have an operation hook that will allow users to clean up after an error. I still don't think we should to add before/after validate hooks. Can you please describe scenarios/use-cases where you need these new hooks? |
@bajtos sure, a However, I still think before/after validate hooks make sense to have, as the Finally, here's a personal issue I would like to point out: I (and many others) go through considerable efforts to create PR's like this - it's getting more and more painful to keep this up with the ongoing (long) discussions that tend to follow. Which frankly, quickly turn into 1:1 discussions. I feel that true open discussions are hampered by the 'structure' which they take place: after the fact, in GH issues. In my previous OS experience, the (core) developer community was much more approachable, with healthy IRC discussions and 1:1 chat sessions to discuss ideas like this, before or while the code is being fleshed out. Sure, I can see you're being protective to keep quality standards and such. But personally I'm getting a bit tired of contributing in such a fashion. Remember, contributions are voluntary, and I often feel that there's more discussion, many more words than LOC, and instead of getting into such a detailed discussion, you could probably whip up a PR that would resolve the issue exactly as you see fit. And we both would be happy, because it feels like a waste of time, sorry. /cc @altsang @raymondfeng |
We moved away from IRC to Gitter, you can find us here: https://gitter.im/strongloop/loopback Please do check with us before starting a larger or possibly controversial change. For posterity, the discussion about what hooks to add is continuing here: strongloop/loopback#1226 (comment) |
@fabien so we are doing all of the things that you'd expect ...but not in the right order and perhaps a bit too much (eg. long 1:1 discussions)? I like the idea of having more discussions in realtime to avoid lengthy PR threads. Does gitter support PMs? If so maybe we could try that... |
@fabien based on our discussion in strongloop/loopback#1226, I am proposing to close this pull request in favour of #441, #559 and possibly also #560. Any objections? |
I was trying to implement |
@tekand I am pretty sure the "before save" hook does run before the validation, see this unit-test. Could you please post your code where you observe that model validation is run before the hook? |
I have a model for Attendance, which has a relation to the User model and an attribute as time. The id of the User is not known, but a unique identifier (cardId) is known. Therefore I implemented the before hook to query the user's id based on the cardId
The validation I used:
After thinking about the issue, I think the |
@tekand I think you hit the nail on the head! You need to call if (!cardId) {
return next();
}
User.findOne({where : {cardId : cardId}}, function (err, user) {
if (err) return next(err);
// modify instance/data
next();
}); |
@tekand FWIW, I think |
@bajtos Thank you very much, it works like charm. :) |
The new hook "persist" has been landed on master via #559, I am closing this pull request as no longer relevant. @fabien please do reopen if you disagree. Here is my proposed solution to the problem described in the PR description:
|
Consider the following scenario (which is somewhat similar to what @clarkorz describes here #433):
beforeRemote('create', ...)
uploaded files (multipart/form-data) are handledctx.args.data
so the model will save thisOr more elaborately:
beforeRemote('create', ...)
uploaded files (multipart/form-data) are handledctx.args.data
so the model can use this laterafter validate
hook handler would have moved the file to its permanent destination and update the instance'sfilepath
attribute.At point
4
there should be a way to cleanup any intermediate (but now invalidated/orphaned) data. In this example scenario there's no way to handle everything in the 'safe'after save
handler, because the form-data needs to be parsed first, so there will always be artifacts already created; it cannot be done side-effect-free.This PR introduces such an
after validate
hook, and pairs it with the expectedbefore validate
hook, which is executed after the data has been set - but before the model is actually validated. Just like the now deprecated hook event 'validate'.Ref: #433 (the proposed solution proved unsatisfactory) and pending #262
/cc @raymondfeng @bajtos