Parse-sdk-ios-osx: Unable to save a change to an object's ACL

Created on 7 Aug 2018  路  26Comments  路  Source: parse-community/Parse-SDK-iOS-OSX

  1. Fetch an existing PFObject and confirm that it is not publicly editable
  2. Make it publicly editable
  3. Save the object

Expected: The object is saved to the server as publicly editable
Actual: The object in memory is updated, but the change is not persisted

Example code:

// first fetch an object from the parse server, then...
print("before: \(object.acl?.hasPublicWriteAccess)") // "false"
object.acl?.hasPublicWriteAccess = true
object.saveInBackground { (success, error) in
    // confirm that success is true and error is nil
    print("after: \(object.acl?.hasPublicWriteAccess)") // "true" - object is updated client-side

    // now, re-fetch the same object or check it in Parse Dashboard. It is not saved as publicly editable.
}

All 26 comments

Ok so the object is actually not saved in the backend but no error is sent?

Can you reproduce with VERBOSE=1 on the server and provide the logs?

Correct. Yep I'll do that now and let you know.

Thanks! Really appreciated!

I'm getting nothing at all logged for the save of the ACL. I've confirmed that the line of code is executed (and the closure fires). I've also confirmed that I'm seeing all the other usual verbose logging activity.

Some observations in case they are helpful:

  • isDirty is false for the object after changing the ACL and before saving. Not sure if this is expected. If I change an additional property of the object before saving to make sure isDirty is true, this does not resolve anything - the second property persists as expected but the ACL does not.
  • If I create a new object, save it, and then update its ACL, it works as expected. Only if the object is fetched from the server (and not created on the client) does the issue present itself.

I have some time to investigate further if you can think of anything else that might help.

Interesting that's odd, is it something that're reproducible with the JS SDK?

I'm not sure, how might I test that out? I don't have a web app but I could try something in cloud code maybe?

perhaps directly from cloud code / server locally. The JS SDK works well in node.

I created a cloud function and connected to a button in my UI. The cloud function seems to successfully save the ACL change.

Here is the cloud function I defined - be forewarned, I'm sure this is terrible javascript...

Parse.Cloud.define("testACLChange", function(request, response) {
    console.log("test acl change");
    const noteID = request.params.noteID;
    console.log(noteID);
    const query = new Parse.Query("Note");
    query.equalTo("objectId", noteID);
    query.find()
        .then((notes) => {
            const note = notes[0];
            const acl = note.get("ACL");
            console.log("before: " + acl.getPublicWriteAccess());
            acl.setPublicWriteAccess(true);
            console.log("after: " + acl.getPublicWriteAccess());
            note.save(null, { sessionToken: request.user.getSessionToken() });
            response.success();
     })
     .catch(() =>  {
       response.error("note lookup failed");
     });
});

I verified through the Parse Dashboard that the object's ACL is saved correctly.

Can you provide the Json representation of your object? What version of the server are your running?

Parse Server version is 2.8.2.

As for a json representation, since the server isn't being sent anything when the client saves, I can't get anything from its log. Is there a way to generate it from the iOS client?

I鈥檒l try to reproduce from the server and provide a fix on top of 2.8.3 ASAP

Thanks, let me know if there's anything else that I can provide.

Although - since this isn't hitting the server at all, wouldn't it be a fix in this SDK, not on the server?

The logs when running the server with VERBOSE=1 would really help :)

I don't get any logs remember! The SDK isn't calling through to the server when I save.

From cloud code, you should have some logs no?

I do, but that works as expected- the ACL change persists.

So I tried with the current server version the following code in JS:

  fit('should let ACL ', async () => {
   // create an object
    const object = new Parse.Object('MyObject');
    // Set ACL to public read, no write
    const acl = new Parse.ACL();
    acl.setPublicReadAccess(true);
    acl.setPublicWriteAccess(false);
    object.set('title', 'a title');
    object.setACL(acl);
    // the save succeed
    await object.save();
    acl.setPublicWriteAccess(true);
    object.setACL(acl);
    // this save fails, as expected
    await object.save();
  });

So in the test case I can't reproduce the issue.

which in your case shoud translate as an error in the iOS SDK, object not found.

Full logs:

verbose: REQUEST for [POST] /1/classes/MyObject: {
  "ACL": {
    "*": {
      "read": true
    }
  },
  "title": "a title"
} method=POST, url=/1/classes/MyObject, user-agent=node-XMLHttpRequest, Parse/js2.0.0 (NodeJS 8.10.0), accept=*/*, content-type=text/plain, host=localhost:8378, content-length=177, connection=close, read=true, title=a title
verbose: RESPONSE from [POST] /1/classes/MyObject: {
  "status": 201,
  "response": {
    "objectId": "1KJYs9nVvv",
    "createdAt": "2018-08-07T17:51:31.990Z"
  },
  "location": "http://localhost:8378/1/classes/MyObject/1KJYs9nVvv"
} status=201, objectId=1KJYs9nVvv, createdAt=2018-08-07T17:51:31.990Z, location=http://localhost:8378/1/classes/MyObject/1KJYs9nVvv
verbose: REQUEST for [PUT] /1/classes/MyObject/1KJYs9nVvv: {
  "ACL": {
    "*": {
      "read": true,
      "write": true
    }
  }
} method=PUT, url=/1/classes/MyObject/1KJYs9nVvv, user-agent=node-XMLHttpRequest, Parse/js2.0.0 (NodeJS 8.10.0), accept=*/*, content-type=text/plain, host=localhost:8378, content-length=188, connection=close, read=true, write=true
error: Error generating response. ParseError { code: 101, message: 'Object not found.' } code=101, message=Object not found.

Right, but this isn't a server issue - I think it's in the iOS SDK. I too can successfully save the ACL change from JS (see above). The issue is that when saving from the iOS client, save() doesn't even reach the server - just returns successfully immediately.

that's probably because the object isnt marked as dirty:

can you try:

let acl = object.acl
acl?.hasPublicWriteAccess = true
object.acl = acl // this will mark the object as dirty
object.saveInBackground { (success, error) in
    // confirm that success is true and error is nil
    print("after: \(object.acl?.hasPublicWriteAccess)") // "true" - object is updated client-side

    // now, re-fetch the same object or check it in Parse Dashboard. It is not saved as publicly editable.
}

Yep that's my current workaround, it works. Is this expected behavior then?

yes it's the expected one, as the PFObject doesn,t know it was mutated.

Oh, interesting. With other pointer properties, that is intuitive - you save the thing you changed, not it's parent object. It would be cool to be able to call save on the ACL itself then, to match. I think that's what tripped me up - having to re-set a property to it's existing value isn't very intuitive, and we don't have the option of doing object.acl.save().

(Thanks for all the help by the way).

ACL is just a simple wrapper object, not 'active' inside the SDK. It's pretty much the same if you mutate local dictionary values in your object, it won't save unless you set it explicitely. At the moment, saving the ACL would need to have a back pointer to the parent which is unnecessary, but could be implemented.

I understand. In the absence of anything more useful to contribute, I wrote this up on StackOverflow in case someone else comes across the same thing.

https://stackoverflow.com/questions/51733025/changing-the-acl-on-a-pfobject-does-not-persist-to-the-parse-server

Great idea to add it there! Thanks :)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

otymartin picture otymartin  路  3Comments

mnearents picture mnearents  路  3Comments

talkaboutdesign picture talkaboutdesign  路  8Comments

kingmatusevich picture kingmatusevich  路  9Comments

devKC picture devKC  路  5Comments