6

I am interested in saving attributes to users in the database based on actions that are performed by my currentUser. Based on the following code, I get the error message "User cannot be saved unless they have been authenticated via logIn or signUp"

NSString *IDToFetch = @"some_id";
PFQuery *query = [PFUser query];
[query whereKey:@"user_id" equalTo:IDToFetch];
PFUser *foundUser = (PFUser *)[query getFirstObject];

foundUser[@"new_column"] = @"Some text";
[foundUser saveEventually]; //here an exception is thrown

I was wondering if there is a work around to this where I could save attributes to the foundUser without having to log that user on. Thanks for your help!

Björn Kaiser
  • 9,882
  • 4
  • 37
  • 57
daspianist
  • 5,336
  • 8
  • 50
  • 94
  • 1
    I've encountered the same problem but I can't recommend our work around. (create a new table for "other" user variables") It's possible cloud code can touch the user objects, so that could be a work around, but I don't know. – Pork 'n' Bunny Sep 06 '13 at 04:01
  • @Pork I may be going this route as well. Were there any issues that made this workaround not a good one? I'd imagine besides the additional queries performed there shouldn't be any major issues..? If you could share your experience with this it'd be great - thanks! – daspianist Sep 08 '13 at 04:34

2 Answers2

12

If you want to update a user that is not currently the logged in user you will need to call Parse using the master-key.

You can do this from CloudCode for example;

Parse.Cloud.define('editUser', function(request, response) {
    var userId = request.params.userId,
        newColText = request.params.newColText;

    var User = Parse.Object.extend('_User'),
        user = new User({ objectId: userId });

    user.set('new_col', newColText);

    Parse.Cloud.useMasterKey();
    user.save().then(function(user) {
        response.success(user);
    }, function(error) {
        response.error(error)
    });
});

and calling it from your iOS project;

[PFCloud callFunction:@"editUser" withParameters:@{
    @"userId": @"someuseridhere",
    @"newColText": @"new text!"
}];
hank
  • 3,748
  • 1
  • 24
  • 37
  • Thanks for the code @hank. I am getting the error `Error: {"code":201,"message":"missing user password"} (Code: 141, Version: 1.2.11)`. My users are all Facebook users, and I am unsure whether this is an issue related to it. – daspianist Sep 06 '13 at 22:07
  • @hank any chance you could help me? I'm trying to use your solution but with a small change and having lots of trouble. Would really appreciate the help. Here's the link: http://stackoverflow.com/questions/22430652/adding-a-user-to-pfrelation-using-parse-cloud-code – user3344977 Mar 15 '14 at 23:07
  • 6 months later and I finally realized what a great answer this is. Thanks! – daspianist Mar 27 '14 at 22:50
  • May I ask what 'new_col' is ? Is that the object key or is newColText the object key ? Also do you have a swift version to call it? – Syed Ariff Apr 04 '16 at 14:24
  • Hi, I have used same function but not successful for me getting this error: "Parse.Cloud.define is not a function". – Naresh Sep 16 '16 at 14:32
  • Parse.Cloud.useMasterKey(); has been deprecated in Parse Server version 2.3.0 (Dec 7, 2016). From that version on, it is a no-op (it does nothing). You should now insert the {useMasterKey:true} optional parameter to each of the methods that need to override the ACL or CLP in your code. – alvaro Jun 01 '17 at 00:36
2

OK Providing this as an answer but basically not recommending it! I think the cloud code route is cleaner at the end of the day. But, this is arguably easier..

You can create another table that pairs with each user.

eg.

table name

user_extra_details

fields

User

Score

so other users can edit this particular field on user_extra_details

But as you suspect this can lead to lots of extra queries but it's not impossible, just... inconvenient. So here's how you'd access your data in that set up.

PFQuery *userQuery = [PFQuery queryWithTable:@"Users"];
[userQuery whereKey:Some Key equalTo:some value];

PFQuery *userDetails [PFQuery queryWithTable:@"user_extra_details"];
[userDetails whereKey:@"User" inQuery:userQuery];
[userDetails includeKey:@"User"];
[userDetails fetch];

The thinng you have to be wry about is that duplicate details objects will create multiple results obviously. So I suggest doing a delete and insert vs doing an update of the extra_detail object to help combat any erroneous duplicates.

Pork 'n' Bunny
  • 6,740
  • 5
  • 25
  • 32
  • 3
    Really, you've stumbled on to the best approach. It's much better to have a separate table like this. And for sure, just as you say you must 'clean as you go'. It's totally normal to have to do this in the cloud. Looks great. – Fattie Dec 23 '13 at 21:36