2

I fear that I know the answer to this, but I'll throw it out here. Is there any way of getting a beforeSave method to trigger on all Parse.Object subclasses using Cloud Code?

So I want to run some code on all saves, not any specific subclass of Parse's Object.

I've tried this:

Parse.Cloud.beforeSave(Parse.Object, function(request, response) {
}

... but it doesn't seem to get triggered.

Darren Black
  • 1,030
  • 1
  • 9
  • 28

3 Answers3

3

I have never heard of this, and, frankly, don't see much benefit. That first parameter is supposed to match a class name, so I doubt there is a work around for this out of the box.

You really should have all separate beforeSave's, though. We create a separate folder within our cloud code for each class, and give each class a Controller (beforeSave, afterSave, cloud functions related directly to the class) which has cloud functions that call other Repos which handle logic for different classes. The Controller is the only file that should touch the Repos from other classes.

Then there is the Repo for each class, which handles doing a specific task / logic, and often saves or fetches objects.

Then there are Factory files, which do no saves, no fetches, no extra calls. They ONLY perform business logic with available data passed in.

Every time you make a new Parse Class, I'd get in the habit of setting up that controller and you can add a beforeSave trigger there.

Jake T.
  • 4,308
  • 2
  • 20
  • 48
  • ... and presumably you have to trigger these Controllers' methods from main.js? (sorry, not usually a JS guy). Either way, in this case, I need to perform the same operations on all saved objects, which makes maintaining separate codebases for each type seem like overkill. And the docs do say that we can provide the class name of a Parse-defined JS object (their example is Parse.User), so I would have expected Parse.Object to work here... but alas it doesn't. – Darren Black May 11 '17 at 15:09
  • Parse.User is a specific subclass of Parse.Object, though, and translates to "_User" when used in that context. It may seem like overkill for your specific needs, but it's best practice when maintaining a code base. And consider if you have 100 classes with a generic beforeSave. What happens when you need to something custom with just one of them? It breaks the whole set up. Doing separate beforeSave's is the obvious right choice. In order for all of the Parse.Cloud end points to be available from other files, you need to include the files they're in at the top of main. – Jake T. May 11 '17 at 15:16
  • The top of my main.js has several lines like `var customClassController = require('./CustomClass/customClassController.js');` – Jake T. May 11 '17 at 15:17
  • That enables all cloud functions, jobs, and save triggers to be accessible on my server. Additionally, you can do `var customClassRepo = require('./CustomClass/customClassRepo.js');` and then can access all the export functions from that repo to use within main. Although, we've been working on trimming main down as much as possible, and those functions really ought to be inside the class controllers. – Jake T. May 11 '17 at 15:18
  • I can confirm a generic object don't work @DarrenBlack, however, that makes me wonder why you would have a before save on ALL Classes that is exactly the same. Did you investigate Class Level Permissions if it's for security purposes? – flovilmart May 13 '17 at 02:04
  • @flovilmart it is for security, but the model is more dynamic than class level permissions can provide. I'm looking to dynamically set ACL's per-object, given a field in the saved object (there are 3 different levels of sharing possible), and some group / role membership context. – Darren Black May 14 '17 at 09:33
  • 2
    you can achieve it with CLP and roles and pointer permissions IMHO. Otherwise: ['Class1', 'Class2', 'Class3'].forEach((className) => { Parse.Cloud.beforeSave(className, mySecurityFunction); }); Also, I guess you don't create new classes everyday right? – flovilmart May 15 '17 at 18:53
  • 1
    Keep in mind the way CLPs and ACLs work is that a user must first pass the CLP (be it through a role, public access, or a pointer permission), then must pass the ACL of the specific object. So, you could have ACL permissions for a specific object for a user, but if the CLP doesn't allow public read/write, and you don't pass a pointer or role permission for that class, you still couldn't find/get/write to that object. It sounds like you just need to modify the ACL to have appropriate permissions for a role, and if only a couple users should have access, use pointer permissions. – Jake T. May 15 '17 at 19:41
  • @flovilmart Thx for the one-liner! I hadn't noticed Pointer Permissions before; they're pretty cool. But I'd still need to set the values in a beforeSave method as far as I can tell. I've gone the ACL route. And you are correct sir! We only plan to introduce 2 of these classes per year. – Darren Black May 19 '17 at 07:55
  • Once a user is signed in, the Parse REST API allows users to make a POST call to /parse/classes/AnyOldThing and it will create a new collection call AnyOldThing and stick a basic object in it. The problem is that at the time beforeSave is called the Cloud code doesn't know about the new class AnyOldThing - so ideally we could use Parse.Object and then check the class to see if it already exists and accept or reject the call on that basis. Or is there another way to prevent Collection proliferation? – Al. May 18 '22 at 13:43
0

No you cannot. You only can make triggers to user defined classes and predefined classes. if the class is user defined, first parameter must be a string e.g.

Parse.Cloud.beforeSave("Car", function(request, response) {
...
}

if the class is predefined, first parameter must Parse.ClassName e.g.

Parse.Cloud.beforeSave(Parse.User, function(request, response) {
...
}
Hatim
  • 1,516
  • 1
  • 18
  • 30
0

You could first get all class names querying the schema (see this post) and then use a forloop to add to each one the beforeSave hook. In pseudo code:

var classNames = getClassNamesFromSchemaQuery();
classNames.foreach(var classObject){
    Parse.Cloud.beforeSave(classObject.className, (req, resp){
        // resto of the code here
    })
}
Raschid JFR
  • 580
  • 8
  • 15