Meteor-Community-Packages / meteor-collection-hooks

Meteor Collection Hooks
https://atmospherejs.com/matb33/collection-hooks
MIT License
657 stars 92 forks source link

Cancel db save operations #78

Closed dalgard closed 9 years ago

dalgard commented 9 years ago

Can I use collection-hooks to do a last-minute circumvention of any actual save operations to the local Mongo db?

I want everything to run like normal with all validation/authorization hooks being in effect – and then, at the last moment, persist the document to a remote end-point instead, leaving the local db untouched.

I could use the deny hook, but it's not optimal for two reasons:

  1. It clutters the authorization code
  2. It throws an exception
matb33 commented 9 years ago

Hmm maybe. Perhaps by returning false in your server before hooks (https://github.com/matb33/meteor-collection-hooks#additional-notes)?

dalgard commented 9 years ago

Oh, sorry – can't believe I missed that. Looks interesting. The "underlying method" you talk about, I suppose, is the collection.insert method, for example?

Then... does that mean, that the collection hook (i.e. .before.insert) is only run in the same context as the originating operation? It would appear that if I do a console.log("my message") inside a .before.insert hook and write collection.insert({...}) in the browser console, "my message" is only printed in the console of the browser, not of the server?

But if that is true, a project like collection-behaviors, building on collection-hooks doesn't in any way guarantee that some extra data is written to the object, since anyone with bad intentions and a console could bypass the hook clientside?

matb33 commented 9 years ago

The underlying method is actually _collection.insert -- that one is available only on the server and is what I rely on to make sure hooks on the server are only called after allow/deny has had a chance to run.

So try declaring your before hook in server code only.

dalgard commented 9 years ago

Oh, that's what I hoped – very cool indeed.

Just to clear things up, if you don't mind too much: If I declare my .before.insert and .after.insert hooks in a file that is loaded both by the browser and the server, do the hooks run in both places?

matb33 commented 9 years ago

Yup, though I find most of my hooks are server only with the exception of those where I modify createdAt/modifiedAt and similar properties -- those i declare in shared code.

dalgard commented 9 years ago

I'm not sure what situation would benefit from modifying the document in both places, but I suppose there might be some UI change triggered. Wouldn't be isomorphic code, though – hmmm, latency compensation...?

Anyway, if I understand correctly, the order when doing a collection.insert({ ... }) in the browser would look like this?

  1. collection.before.insert is run in the browser
  2. collection.deny is run on the server
  3. collection.allow is run on the server
  4. collection.before.insert is run on the server
  5. collection.after.insert is run on the server
  6. collection.after.insert is run in the browser
matb33 commented 9 years ago

I think your order is correct. I sure hope it is! I now realize I don't have a test that verifies this.

And indeed the idea with declaring a hook in a shared area would be to accomplish latency compensation. So for example, a default schema for your object in before.insert (createdAt and other initial properties), and updating a modifiedAt date in the before.update. If the client and server diverge, such as the common case for time, we can count on Meteor taking the server's version as authoritative and pushing the change back to the client anyway.

But when using a hook to trigger an action such as sending an email notification etc, those don't make much sense on the client.

dalgard commented 9 years ago

Awesome – thanks! This has helped me immensely in my project.