Can't write non current user objects by PFUser currentuser
For security reasons, Parse won't allow you to save any changes to a user that is not currently logged in.
If you want to be able to make and save changes to user
, you need to use Cloud Code
and the Master Key
to get around this roadblock.
I have had multiple problems like this before, and every time I've been forced to use a workaround via Cloud Code
.
Here's an example of a workaround I did for creating a friends relationship between two users:
[PFCloud callFunction:@"editUser" withParameters:@{@"userId": user.objectId}];
The above code statement is in xcode, and executes the function I have added to my Cloud Code
file.
Then, here's what my Cloud Code
file looks like:
Parse.Cloud.define('editUser', function(request, response) {
var userId = request.params.userId;
var User = Parse.Object.extend('_User'),
user = new User({ objectId: userId });
var currentUser = request.user;
var relation = user.relation("friendsRelation");
relation.add(currentUser);
Parse.Cloud.useMasterKey();
user.save().then(function(user) {
response.success(user);
}, function(error) {
response.error(error)
});
});
The above code uses the Master Key
to save changes to both the currently logged in user, and to the user who's objectId was passed into this function.
Code details:
var relation
This is just a variable I'm creating to hold what the following fucntion returns:
user.relation("friendsRelation");
In the above function, "friendsRelation"
is the name of my PFRelation key in Parse.
Now that we have a valid relation object contain in our variable called relation
, we execute this function with an argument of our currentUser
object.
After that, all that's left is saving everything. I don't program with javascript, but I was still able to come up with the above solution by looking at the Parse Cloud Code
docs, and searching around on their support forums.
If you take my template from above, and make some small changes, then you should be able to easily accomplish what you need. You just have to jump through these extra hoops because the Parse SDK
doesn't want a situation where someone can login and somehow make changes to another user's account, whether by their own fault or a developer's mistake.
EDIT:
Here is the code to add the relationship for the current user:
PFRelation *friendsRelation = [[PFUser currentUser]relationforKey:@"friendsRelation"];
PFUser *user = [self.parseUsers objectAtIndex:indexPath.row];
[friendsRelation addObject:user];
[currentUser saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (error) {
NSLog(@"%@ %@", error, [error userInfo]);
}
}];
And then you can call the Cloud Code method right after:
[PFCloud callFunction:@"editUser" withParameters:@{
@"userId": user.objectId
}];
Parse PFUser.currentUser returns nil - Swift
I discovered that this problem appeared because the segue signInToNavigation
was wired from the Login-button, instead from the login view controller itself. This resulted in the segue being executed before the login function was executed, and therefore the PFUser.currentUser()
object was not yet assigned when the table view loaded. I solved this by rewiring the segues. Stupid slip-up on my side.
Thanks to Ryan Kreager and Wain for taking time to help me figure out this issue!
Query on local datastore with [PFUser currentUser] returns no objects
As per our discussion above;
Provided you have an active PFUser session, then that user will autonomously be designated as the owner. Even if you don't have a current session and there is no [PFUser currentUser]
local datastore is owned by the device. For now, local datastore is prejudice. Since apps are sandboxed and you have no writing privileges outside of your own resource bundle, another user can not change alter/update your local datastore. Even with the backend, you can not update any users information in the User class, unless your the current user or have writing privileges. With local datastore, it's always assumed you are the "current user", regardless of the session. However, if you do want to ignore Roles for protected information in local datastore you can see their notes here :
https://parse.com/docs/ios_guide#users-lds/iOS
The same security model that applies to objects in Parse applies to objects in the Local Datastore. Read-write permissions are defined by PFACLs and a user cannot access or modify anything they don't have permission to.
The only difference is that you won't be able to access any data protected by Role based ACLs due to the fact that the Roles are stored on the server. To access this data protected by Role based ACLs, you will need to ignore ACLs when executing a Local Datastore query
However, I don't feel you need this considering your circumstance.
Define mutual relation between two user with Parse JavaScript
You aren't changing the currentUser
so calling currentUser.save()
will not do anything.
Also when getting an existing user you should do the following:
Parse.Cloud.define('editUser', function(request, response) {
Parse.Cloud.useMasterKey();
var userQuery = new Parse.Query(Parse.User);
userQuery.get(request.params.userId)
.then(function (user) {
var relation = user.relation("sampleRelation");
relation.add(request.user);
// chain the promise
return user.save();
}).then(function (user) {
var currentUser = request.user;
var relation = currentUser.relation("sampleRelation");
relation.add(user);
// chain the new promise
return currentUser.save();
}).then(function () {
response.success();
}, function (error) {
response.error(error);
});
});
Parse doesn't return PFObject
Parse doesn't fetch for you automatically, except a few pieces of data in specific scenarios. Like, when a user logs in the current user will be fetched and will include the standard user data - but it won't include any custom data.
If you fetch an object then that objects details will be downloaded, but the details of related objects won't - unless you specifically request it to be included in the query that you make (using includeKey:
).
It's generally best to always use fetchIfNeededInBackgroundWithBlock:
if you aren't sure whether the data you need has been obtained yet. Not doing this shouldn't cause a crash but it will generally cause you issues with missing information. It's possible that the crash is related to parse using exceptions for navigation in the framework, but that's a guess and you might want to try contacting parse to see if you can get more details.
Subclassing PFUser. Accessing current user
If you check PFUser.h
in Parse library, you will see currentUser
returns instancetype
.
+ (instancetype)currentUser;
This means that if you subclass PFUser
, then currentUser
returns an object of the type of the subclass, which is MyUserSubclass
in your case.
Here is a short example of subclassing PFUser
:
User.h
#import <Parse/Parse.h>
@interface User : PFUser <PFSubclassing>
@property (nonatomic, strong) NSString *firstName;
+ (User *)user;
+ (BOOL)isLoggedIn;
@end
User.m
#import "User.h"
#import <Parse/PFObject+Subclass.h>
@implementation User
@dynamic firstName;
+ (User *)user {
return (User *)[PFUser user];
}
+ (BOOL)isLoggedIn
{
return [User currentUser] ? YES: NO;
}
@end
Notice that I need to implement a +(User *)user;
method, because in PFUser.h
it is +(PFUser *)user;
rather than instancetype
.
PFUser Subclassing: Local-Only (non-db) User Properties?
I would override the saveInBackground:
method in your PFUser subclass in order to accomplish your goal. Something like this:
Header file:
@interface PFUserSubclass : PFUser
@property (nonatomic, strong) NSString *customPropertyToSave;
@property (nonatomic, strong) NSString *customPropertyToIgnore;
- (void)saveInBackgroundWithBlock:(PFBooleanResultBlock)block;
@end
Implementation file:
@implementation PFUserSubclass
@synthesize customPropertyToSave;
@synthesize customPropertyToIgnore;
- (void)saveInBackgroundWithBlock:(PFBooleanResultBlock)block {
PFUser *userToSave = [PFUser currentUser];
[userToSave setObject:self.customPropertyToSave forKey:@"customProperty"];
[userToSave saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
block(succeeded, error);
}];
}
@end
Related Topics
Problems with Layout of Some Rows in Swiftui List
Wkwebview Allowslinkpreview to False Breaks Text Selection
How to Make a Countdown Timer Like in a Music Player
Adding an Skscene to a Uiviewcontroller
How Is a Swift Cgvector Created with Dx and Dy (Derivative)
Uicollectionviewcompositionallayout - Center Items in Sections or Groups
iOS - Running Background Task for Update User Location Using Swift
No Such Module Iqkeyboardmanagerswift
-Webkit-Overflow-Scrolling: Touch' Broken for Initially Offscreen Elements in iOS7
iOS 7 Weather App Expand/Collapse Transition
Programmatically Change Splash Screen in iOS
Strange Custom Background Color on Uipickerview Swift
How to Make a Reusable Tableview for Different Screens in the Same Application
iOS 8 Code Working on iPhone 5S But Not iPhone 5
Cannot Subscript a Value of [Anyobject]? with an Index of Type Int
Detecting Double and Single Tap on Uitableviewcell to Perform Two Action