How to Post to database via RestKit 0.20 - ios

I am trying to POST to an API using restkit.
When I press save post- I get an error showing an empty post and alert saying:
Expected status code in (200-299), got 422" UserInfo=0xb83ca20 {NSLocalizedRecoverySuggestion={"body":["can't be blank"]},
The post is displayed in the tableView but the text I entered doesn't make it to the database.
Any ideas why this might be? The usual problems I've seen are because people are missing parsing the data to json or because they lack a responseDescriptor - but I have this and I'm not getting the json error. It's just not retaining the text I enter.
Why is this?
My savePost method is like this
RKManagedObjectStore *objectStore = [[RKObjectManager sharedManager] managedObjectStore];
Post *post = [NSEntityDescription insertNewObjectForEntityForName:#"Post" inManagedObjectContext:objectStore.mainQueueManagedObjectContext];
[post setBody:self.postTextField.text];
[objectStore.mainQueueManagedObjectContext save:nil];
RKObjectManager *manager = [RKObjectManager sharedManager]; [manager postObject:self path:#"/posts.json" parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
NSLog(#"Success saving post");
// [MUser setCurrentUser:self];
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#"Failure saving post: %#", error.localizedDescription);
}];
And in my appDelegate I have this setup:
NSError *error = nil;
NSURL *modelURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#"Markofresh" ofType:#"momd"]];
// NOTE: Due to an iOS 5 bug, the managed object model returned is immutable.
NSManagedObjectModel *managedObjectModel = [[[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL] mutableCopy];
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel];
// Initialize the Core Data stack
[managedObjectStore createPersistentStoreCoordinator];
NSPersistentStore __unused *persistentStore = [managedObjectStore addInMemoryPersistentStore:&error];
NSAssert(persistentStore, #"Failed to add persistent store: %#", error);
[managedObjectStore createManagedObjectContexts];
// Configure a managed object cache to ensure we do not create duplicate objects
managedObjectStore.managedObjectCache = [[RKInMemoryManagedObjectCache alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
// Set the default store shared instance
[RKManagedObjectStore setDefaultStore:managedObjectStore];
// Configure the object manager
RKObjectManager *objectManager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:#"https://fierce.herokuapp.com"]];
objectManager.managedObjectStore = managedObjectStore;
[objectManager setRequestSerializationMIMEType:#"application/json"];
[objectManager setAcceptHeaderWithMIMEType:#"application/json"];
[RKObjectManager setSharedManager:objectManager];
//setup Post Entity map
RKEntityMapping *entityMapping = [RKEntityMapping mappingForEntityForName:#"Post" inManagedObjectStore:managedObjectStore];
[entityMapping addAttributeMappingsFromDictionary:#{
#"id": #"postID",
#"url": #"jsonURL",
#"body": #"body",
#"created_at": #"createdAt"}];
entityMapping.identificationAttributes = #[ #"postID" ];
[RKObjectManager sharedManager].requestSerializationMIMEType = RKMIMETypeJSON;
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:entityMapping pathPattern:#"/posts.json" keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[objectManager addResponseDescriptor:responseDescriptor];
RKRequestDescriptor *requestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:[entityMapping inverseMapping] objectClass:[Post class] rootKeyPath:#"/posts.json"];
[objectManager addRequestDescriptor:requestDescriptor];
I have seen other people get hung up on this and wonder if maybe AFNetworking might be a better choice for this kind of simple method- and there's more documentation on it as well.
I know what I'm trying to do is simple and I don't get what is causing the empty post. Any help would be greatly appreciated.

Should you be doing:
[manager postObject:post path:#"/posts.json" parameters:nil ...
So your issue is simply a typo?
Try turning on mapping trace logging so you can see what's happening:
RKLogConfigureByName("RestKit/ObjectMapping", RKLogLevelTrace);
And think about something like the Charles Proxy to show you exactly what's hitting the wire.

Related

iOS - get objects from RESTful service with RestKit

I am trying to get data from my RESTful services. I get this code from some tutorials and I hope I get it right. I think I am just missing something. I get this:
RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:#"http://www....com"]];
NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel];
manager.managedObjectStore = managedObjectStore;
NSDictionary *parentObjectMapping = #{
#"lat" : #"latitude",
#"long" : #"longitude",
};
RKEntityMapping *cityMapping = [RKEntityMapping mappingForEntityForName:NSStringFromClass([City class]) inManagedObjectStore:managedObjectStore];
[cityMapping addAttributeMappingsFromDictionary:#{
#"name" : #"name",
#"country" : #"country",
#"population" : #"population",
}];
[cityMapping addAttributeMappingsFromDictionary:parentObjectMapping];
[manager addResponseDescriptorsFromArray:#[[RKResponseDescriptor responseDescriptorWithMapping:cityMapping
pathPattern:nil
keyPath:#"results"
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)]
]];
[manager getObjectsAtPath:#"/api/autocomplete?q=bos"
parameters:nil
success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult)
{
}
failure:^(RKObjectRequestOperation *operation, NSError *error)
{
}];
Last few lines I added because I think I was missing something like execute. Now when I run this I get error:
Unable to perform mapping: No `managedObjectContext` assigned.
How can I fix this? Did I make other things allright? Thanks
As the error already suggests: you are missing the managedObjectContext. Add it using [managedObjectStore createManagedObjectContexts]; (the line after creating the store itself)

POST with RestKit 0.20 - NSManagedObjectContext issue

I'm trying to make a POST request with RestKit, but when I call the postObject method of my RKObjectManager I get the following error :
Can only use -performBlockAndWait: on an NSManagedObjectContext that was created with a queue.
This error came when the method performBlockAndWait is called by the RKManagedObjectRequestOperation class.
Here is my code :
RKObjectMapping *responseMapping = [RKObjectMapping requestMapping];
[responseMapping addAttributeMappingsFromDictionary:#{
// ...
}];
NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful); // Anything in 2xx
NSString *pathPattern = #"myPath";
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:responseMapping method:RKRequestMethodPOST pathPattern:pathPattern keyPath:nil statusCodes:statusCodes];
RKObjectMapping *requestMapping = [RKObjectMapping requestMapping];
[requestMapping addAttributeMappingsFromDictionary:#{
// ...
}];
RKRequestDescriptor *requestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:requestMapping objectClass:[MyClass class] rootKeyPath:#"" method:RKRequestMethodPOST];
NSURL *baseURL = [NSURL URLWithString:#"http://192.168.1.1:8080"];
RKObjectManager *manager = [RKObjectManager managerWithBaseURL:baseURL];
[manager addRequestDescriptor:requestDescriptor];
[manager addResponseDescriptor:responseDescriptor];
NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel];
manager.managedObjectStore = managedObjectStore;
[managedObjectStore createPersistentStoreCoordinator];
NSString *storePath = [RKApplicationDataDirectory() stringByAppendingPathComponent:#"mySqliteDatabaseFile"];
NSError *error;
NSPersistentStore *persistentStore = [managedObjectStore addSQLitePersistentStoreAtPath:storePath fromSeedDatabaseAtPath:nil withConfiguration:nil options:nil error:&error];
NSAssert(persistentStore, #"Failed to add persistent store with error: %#", error);
[managedObjectStore createManagedObjectContexts];
managedObjectStore.managedObjectCache = [[RKInMemoryManagedObjectCache alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
// POST to create
#try {
[manager postObject:visitReport path:#"myPath" parameters:nil success:^( RKObjectRequestOperation *operation , RKMappingResult *mappingResult ) {
NSLog(#"Success");
} failure:^( RKObjectRequestOperation *operation , NSError *error ){
NSLog(#"Failure - %#",error);
}];
}
#catch (NSException *exception) {
NSLog(#"error - %#", exception);
}
I don't understand the problem with my context, any help is welcomed.
Thank you.
Ok finally I find the problem :
The object visitReport I tried to POST is not from the NSManagedObjectContext expected by RestKit.
To solve, I create a new object :
MyObject *visitReportContext = [NSEntityDescription insertNewObjectForEntityForName:#"tableName"
inManagedObjectContext:objectStore.mainQueueManagedObjectContext];
visitReportContext.Id = visitReport.Id
visitReportContext.title = visitReport.title
// etc..
Then, when I POST my new object, it works. But it's not very beautiful... How can I deal with my old object visitReport without create a new one in this "RestKit context" ?

Restkit - Post object

I try to post an object Foobar (the class has two attributes: string foo and string bar) using the method postObject of the class RKObjectManager.
Server-side, I have a WCF service that receive the POST method
public void PostFoobar(Foobar foobar) { ... }
All the connection works. The problem is that the object foobar received is always NULL. It seems ResKit does not POST my object as an encapsulation of the two arguments, but post two string independently.
I mean, when I tryed to implement the following method (server-side) :
public void PostFoobar(string foo, string bar) { ... }
and the two parameters was not null ! it has worked !
But I would prefer to recover the serialized object obviously...
My question is :
How am I suppose to configure my POST request to recover an entire Foobar object on the server side, and not every attributes independently ?
My code
Here is my code to send the POST request
NSError *error = nil;
NSManagedObjectModel *managedObjectModel = #"myObjecModel";
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel];
[managedObjectStore createPersistentStoreCoordinator];
NSPersistentStore __unused *persistentStore = [managedObjectStore addInMemoryPersistentStore:&error];
NSAssert(persistentStore, #"Failed to add persistent store: %#", error);
[managedObjectStore createManagedObjectContexts];
managedObjectStore.managedObjectCache = [[RKInMemoryManagedObjectCache alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
[RKManagedObjectStore setDefaultStore:managedObjectStore];
// Configure the object manager
RKObjectManager *objectManager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:#"http://192.168.1.10/rest"]];
objectManager.managedObjectStore = managedObjectStore;
objectManager.requestSerializationMIMEType = RKMIMETypeJSON;
[objectManager setAcceptHeaderWithMIMEType:RKMIMETypeJSON];
[RKObjectManager setSharedManager:objectManager];
[RKMIMETypeSerialization registerClass:[RKNSJSONSerialization class] forMIMEType:#"text/plain"];
RKEntityMapping *postMapping = [RKEntityMapping mappingForEntityForName:#"Foobar" inManagedObjectStore:managedObjectStore];
[postMapping addAttributeMappingsFromDictionary:#{
#"foo" : #"strFoo", // server side:foo, iOS side: strFoo
#"bar" : #"strBar" // server side:bar, iOS side: strBar
}];
RKRequestDescriptor * requestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:[postMapping inverseMapping] objectClass:[Foobar class] rootKeyPath:nil method:RKRequestMethodPOST];
[objectManager addRequestDescriptor:requestDescriptor];
// POST to create
RKManagedObjectStore *objectStore = [[RKObjectManager sharedManager] managedObjectStore];
Foobar *foobar = [NSEntityDescription insertNewObjectForEntityForName:#"Foobar" inManagedObjectContext:objectStore.mainQueueManagedObjectContext];
foobar.strFoo = #"foo ipad";
foobar.strBar = #"bar ipad";
#try {
[[RKObjectManager sharedManager] postObject:foobar path:#"foobar" parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
NSLog(#"Success");
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#"Failure: %#", error.localizedDescription);
}];
}
#catch (NSException *exception) {
NSLog(#"error - %#", exception);
}
One more thing :
I have tested my web service with the chrome client "Simle REST client" and it works with the data :
{ "foo": "foo from chrome", "bar" : "bar from chrome" }
Edit - Frame capture with Wireshark
It seems to be good.. I don't understant.
You're calling with nil:
[[RKObjectManager sharedManager] postObject:nil path:#"foobar" parameters:nil ...
So RestKit is given nothing to serialise and no parameters.
If that's a typo, turn on trace logging for mapping and look at what it's doing. Also, get Charles or a similar tool and check exactly what data is being sent over the network.

iOS RestKit issue: Invalid parameter not satisfying: responseDescriptors

I am trying to use RestKit to retrieve a listing of events and I keep getting this:
2013-05-20 10:52:56.708 EventApp[3380:c07] I restkit:RKLog.m:34 RestKit logging initialized...
2013-05-20 10:52:56.773 EventApp[3380:c07] *** Assertion failure in -[RKObjectRequestOperation initWithRequest:responseDescriptors:], /Users/mitchell/Desktop/eventapp/take2/EventApp/Pods/RestKit/Code/Network/RKObjectRequestOperation.m:158
2013-05-20 10:52:56.774 EventApp[3380:c07] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid parameter not satisfying: responseDescriptors'
I have been scratching my head for days on this one. As I have a fair amount of gaps in my iOS dev skills(about one project every year) it would greatly help if someone can just lead me in the right direction here using some laymen terms.
Please consider that I am looking to use enqueueObjectRequestOperation specifically for batching multiple requests. I have just pieced together bits of my code for translation here.
Here is what my datamodel looks like:
Here is the what the JSON file looks like:
[{
"id":1,
"farm_id":1,
"all_day": "NO",
"from": "2013-05-08T18:45:38Z",
"to": "2013-05-08T18:45:38Z",
"name": "event 1",
"desc": "some description",
"photo": "some.png",
"price": "price"
}]
Here is my code:
NSManagedObjectContext *context;
RKObjectManager *objectManager;
if (self.eventContext == nil) {
NSError *error = nil;
NSURL *modelURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#"FarmApp" ofType:#"momd"]];
RKEntityMapping *entityMapping;
// NOTE: Due to an iOS 5 bug, the managed object model returned is immutable.
NSManagedObjectModel *managedObjectModel = [[[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL] mutableCopy];
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel];
// Initialize the Core Data stack
[managedObjectStore createPersistentStoreCoordinator];
NSPersistentStore __unused *eventPersistentStore = [managedObjectStore addInMemoryPersistentStore:&error];
NSAssert(eventPersistentStore, #"Failed to add persistent store: %#", error);
[managedObjectStore createManagedObjectContexts];
// Set the default store shared instance
[RKManagedObjectStore setDefaultStore:managedObjectStore];
// Configure the object manager
RKObjectManager *objectManager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:#"http://sandbox.bm.com"]];
[RKObjectManager setSharedManager:objectManager];
[objectManager setRequestSerializationMIMEType:#"application/json"];
[objectManager setAcceptHeaderWithMIMEType:#"text/plain"];
objectManager.managedObjectStore = managedObjectStore;
entityMapping = [RKEntityMapping mappingForEntityForName:#"Event" inManagedObjectStore:managedObjectStore];
[entityMapping addAttributeMappingsFromDictionary:#{
#"id": #"eventID",
#"farm_id": #"farm",
#"all_day": #"allDay",
#"from": #"from",
#"to": #"to",
#"name": #"name",
#"desc": #"desc",
#"photo": #"photo",
#"price": #"price"
}];
RKResponseDescriptor *successDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:entityMapping pathPattern:nil keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[objectManager addResponseDescriptor:successDescriptor];
RKResponseDescriptor *errorDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:entityMapping pathPattern:nil keyPath:#"errors" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassClientError)];
[objectManager addResponseDescriptor:errorDescriptor];
self.eventContext = managedObjectStore.mainQueueManagedObjectContext;
}
context = self.eventContext;
NSString* url = [NSString stringWithFormat:#"http://sandbox.bm.com/farmapp/%#.json", #"events"];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
RKObjectRequestOperation *operation = [[RKObjectRequestOperation alloc] initWithRequest:request responseDescriptors:[objectManager responseDescriptors]];
[operation setCompletionBlockWithSuccess:nil failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#"Loaded this error: %#", [error localizedDescription]);
}];
NSArray *operations = [NSArray arrayWithObjects:operation, nil];
for (int i = 0; i < [operations count]; i++ ) {
[[RKObjectManager sharedManager] enqueueObjectRequestOperation:[operations objectAtIndex:i]];
}
Can someone out there help me?
Here is the final solution
if (self.eventContext == nil) {
NSManagedObjectContext *context;
RKObjectManager *objectManager;
NSError *error = nil;
NSURL *modelURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#"FarmApp" ofType:#"momd"]];
RKEntityMapping *entityMapping;
// NOTE: Due to an iOS 5 bug, the managed object model returned is immutable.
NSManagedObjectModel *managedObjectModel = [[[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL] mutableCopy];
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel];
// Initialize the Core Data stack
[managedObjectStore createPersistentStoreCoordinator];
NSPersistentStore __unused *eventPersistentStore = [managedObjectStore addInMemoryPersistentStore:&error];
NSAssert(eventPersistentStore, #"Failed to add persistent store: %#", error);
[managedObjectStore createManagedObjectContexts];
// Set the default store shared instance
[RKManagedObjectStore setDefaultStore:managedObjectStore];
// Configure the object manager
objectManager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:#"http://sandbox.bm.com"]];
[RKObjectManager setSharedManager:objectManager];
[objectManager setRequestSerializationMIMEType:#"application/json"];
[objectManager setAcceptHeaderWithMIMEType:#"text/plain"];
objectManager.managedObjectStore = managedObjectStore;
entityMapping = [RKEntityMapping mappingForEntityForName:#"Event" inManagedObjectStore:managedObjectStore];
[entityMapping addAttributeMappingsFromDictionary:#{
#"id": #"eventID",
//#"farm_id": #"farm",-->cannot create relationship this way
#"farm_id" : #"farmID",//farmID attribute needs to be added to Event's model
#"all_day": #"allDay",
#"from": #"from",
#"to": #"to",
#"name": #"name",
#"desc": #"desc",
#"photo": #"photo",
#"price": #"price"
}];
[entityMapping addConnectionForRelationship:#"farm" connectedBy:#"farmID"];
RKResponseDescriptor *successDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:entityMapping pathPattern:nil keyPath:#"events" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[objectManager addResponseDescriptor:successDescriptor];
RKResponseDescriptor *errorDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:entityMapping pathPattern:nil keyPath:#"errors" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassClientError)];
[objectManager addResponseDescriptor:errorDescriptor];
self.eventContext = managedObjectStore.mainQueueManagedObjectContext;
context = self.eventContext;
NSString* url = [NSString stringWithFormat:#"http://sandbox.bm.com/farmapp/%#.json", #"events"];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
RKManagedObjectRequestOperation *operation = [objectManager managedObjectRequestOperationWithRequest:request managedObjectContext:managedObjectStore.mainQueueManagedObjectContext success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
NSLog(#"Success");
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#"Failure");
}];
NSArray *operations = [NSArray arrayWithObjects:operation, nil];
for (int i = 0; i < [operations count]; i++ ) {
[[RKObjectManager sharedManager] enqueueObjectRequestOperation:[operations objectAtIndex:i]];
}
}
As #JoelH. suggests in one of his comments, you need to use RKManagedObjectRequestOperation instead of RKObjectRequestOperation.
For example :
RKManagedObjectRequestOperation *operation = [objectmanager managedObjectRequestOperationWithRequest:request managedObjectContext:managedObjectStore.mainQueueManagedObjectContext success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
NSLog(#"Success");
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#"Failure");
}];
Besides, I think the way you are mapping
#"farm_id": #"farm"
is not correct.
If you want to build the relationship between Event and Farm, you need to use one of these methods :
relationshipMappingFromKeyPath:toKeyPath:withMapping:
or addConnectionForRelationship:connectedBy:
If the Farm object already exists and you only want to map the new Event, I would go for addConnectionForRelationship:connectedBy:
For example :
RKEntityMapping* eventMapping = [RKEntityMapping mappingForEntityForName:#"Event" inManagedObjectStore:managedObjectStore];
[entityMapping addAttributeMappingsFromDictionary:#{
#"id": #"eventID",
//#"farm_id": #"farm",-->cannot create relationship this way
#"farm_id" : #"farmID",//farmID attribute needs to be added to Event's model
#"all_day": #"allDay",
#"from": #"from",
#"to": #"to",
#"name": #"name",
#"desc": #"desc",
#"photo": #"photo",
#"price": #"price"
}];
[eventMapping addConnectionForRelationship:#"farm" connectedBy:#"farmID"];
It would also require to add a farmID attribute in your Event model, as RestKit does not allow relationship connection without intermediary attributes yet.
The RestKit docs (Mapping Without KVC) seem to imply that if you don't have a KVC label on the top level(e.g. events:[]), a pathPattern: is required for the parser to know which mapping to use. Since both your keyPath: and pathPattern: are nil for your successDescriptor, I have two suggestions:
If changing the JSON structure is possible, change the top level to { events:[...] } and change keyPath:nil to keyPath:#"events" to reflect this change.
If it's not possible, change pathPattern:nil to pathPattern:#"/farmapp" Notice, I set pathPattern: to match your resource URL. This second suggestion might not work if you have other types of resources branching from that URL as well.
Also, I noticed that your errorDescriptor uses the same mapping(entityMapping) as your successDescriptor. I don't know if that's what you intended, but if your error response is supposed to be some different error object, I suggest changing that.
Hope this helps!

How do I create/post a new managed object to server using Restkit 0.20.0?

I'm having a very hard time finding documentation or examples of creating a new managed object, setting it's values, and saving to the server using Restkit.
I have a NSManagedObject Post:
#interface Post : NSManagedObject
#property (nonatomic, retain) NSNumber * postID;
#property (nonatomic, retain) NSString * title;
#property (nonatomic, retain) NSString * text;
#end
This is my AppDelegate Setup:
// ---- BEGIN RestKit setup -----
RKLogConfigureByName("RestKit/Network", RKLogLevelTrace);
NSError *error = nil;
NSURL *modelURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#"My_App" ofType:#"momd"]];
// NOTE: Due to an iOS 5 bug, the managed object model returned is immutable.
NSManagedObjectModel *managedObjectModel = [[[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL] mutableCopy];
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel];
// Enable Activity Indicator Spinner
[AFNetworkActivityIndicatorManager sharedManager].enabled = YES;
// Initialize the Core Data stack
[managedObjectStore createPersistentStoreCoordinator];
NSPersistentStore __unused *persistentStore = [managedObjectStore addInMemoryPersistentStore:&error];
NSAssert(persistentStore, #"Failed to add persistent store: %#", error);
[managedObjectStore createManagedObjectContexts];
// Configure a managed object cache to ensure we do not create duplicate objects
managedObjectStore.managedObjectCache = [[RKInMemoryManagedObjectCache alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
// Set the default store shared instance
[RKManagedObjectStore setDefaultStore:managedObjectStore];
// Configure the object manager
RKObjectManager *objectManager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:#"http://localhost:3000/api/v1"]];
objectManager.managedObjectStore = managedObjectStore;
NSString *auth_token = [[LUKeychainAccess standardKeychainAccess] stringForKey:#"auth_token"]; // Getting the Auth_Token from keychain
[objectManager.HTTPClient setAuthorizationHeaderWithToken:auth_token];
[RKObjectManager setSharedManager:objectManager];
// Setup Post entity mappping
RKEntityMapping *postMapping = [RKEntityMapping mappingForEntityForName:#"Post" inManagedObjectStore:managedObjectStore];
[postMapping addAttributeMappingsFromDictionary:#{
#"title": #"title",
#"text": #"text",
#"id": #"postID"}];
RKResponseDescriptor *postResponseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:postMapping pathPattern:nil keyPath:#"post" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[objectManager addResponseDescriptor:postResponseDescriptor];
Now, In my NewPostViewController when I click my "Save" button I have in my navbar, what do I need to do to save this post to my server?
Here's what I've tried, but it's not working correctly. I enter the success block and my server got the POST, but the fields are nil:
- (void)savePost {
RKManagedObjectStore *objectStore = [[RKObjectManager sharedManager] managedObjectStore];
Post *post = [NSEntityDescription insertNewObjectForEntityForName:#"Post" inManagedObjectContext:objectStore.mainQueueManagedObjectContext];
[post setTitle:#"The Title"];
[post setText:#"The Text"];
[[RKObjectManager sharedManager] postObject:post path:#"posts" parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
NSLog(#"Success saving post");
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#"Failure saving post: %#", error.localizedDescription);
}];
}
It looks like you haven't added any RKRequestDescriptor's to your object manager. Without them, the poor object manager can't use key/value magic to serialize your object into an NSDictionary.
The thing that you HAVE added, the RKResponseDescriptor, describes how responses are managed. That's why you're seeing the success block called: RestKit has no idea what you're trying to send, but it recognizes the Post objects in the server response.
Try adding this below your responseDescriptor code:
RKRequestDescriptor * requestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:[postMapping inverseMapping] objectClass:[Post class] rootKeyPath:#"post"];
[objectManager addRequestDescriptor:requestDescriptor];
(double check the keypath; I don't know what your API expects, so I went with what you had in the response descriptor)

Resources