Question

I'm trying to make the magic happen with RestKit and Rails. I'm using Rails 3.1.1, and RestKit 0.9.3 (not the master branch). I am using Core Data in my iOS app, so I'm trying to setup the app to use as much RestKit magic as possible to interact with the rails app.

However, I'm having a problem trying to POST a new object to my server to be created. I have successfully GET'ed the objects down. Here is my code to do that:

RKObjectManager* manager = [RKObjectManager objectManagerWithBaseURL:@"http://IP_ADDRESS"];
manager.objectStore = [RKManagedObjectStore objectStoreWithStoreFilename:@"magikarp.sqlite"];
manager.client.requestQueue.showsNetworkActivityIndicatorWhenBusy = YES;
manager.acceptMIMEType = RKMIMETypeJSON; 
manager.serializationMIMEType = RKMIMETypeJSON; 

///
/// Setup Routing
///

RKObjectRouter *router = [[RKObjectRouter alloc] init];
[router routeClass:[List class] toResourcePath:@"/lists/(listID)"];
[router routeClass:[List class] toResourcePath:@"/lists" forMethod:RKRequestMethodPOST];
manager.router = router;

///
/// Setup mapping for my "List" object; a subclass of NSManagedObject
///
RKManagedObjectMapping *listMapping = [RKManagedObjectMapping mappingForClass:[List class]];
listMapping.primaryKeyAttribute = @"listID";

[listMapping mapAttributes:@"title", nil];
[listMapping mapKeyPath:@"id" toAttribute:@"listID"];
[manager.mappingProvider setMapping:listMapping forKeyPath:@"list"];

That seems to be working well for me. Now, I want to POST a newly created object back to the server.

- (void)createList:(NSString *)listName {
    List *newList = [List object];
    newList.title = listName;
    [[RKObjectManager sharedManager] postObject:newList delegate:self]; 
}

I call this method with the name I want the new list to have. This method is called, but I get this error:

2011-12-06 19:24:17.822 Magikarp[13921:14c1b] W restkit.object_mapping:RKObjectMapper.m:74 Adding mapping error: Could not find an object mapping for keyPath: ''
2011-12-06 19:24:17.823 Magikarp[13921:14c1b] E restkit.network:RKObjectLoader.m:190 Encountered errors during mapping: Could not find an object mapping for keyPath: ''
2011-12-06 19:24:17.823 Magikarp[13921:14c1b] Hit error: Error Domain=org.restkit.RestKit.ErrorDomain Code=1001 "Could not find an object mapping for keyPath: ''" UserInfo=0x6bb9da0 {=RKObjectMapperKeyPath, NSLocalizedDescription=Could not find an object mapping for keyPath: ''}

The attempt I made to get the mapping done was:

RKObjectMapping *listSerializationMapping = [RKObjectMapping mappingForClass:[NSMutableDictionary class]];
[listSerializationMapping mapKeyPath:@"title" toAttribute:@"title"];
[listSerializationMapping mapKeyPath:@"ListID" toAttribute:@"id"];
[manager.mappingProvider setSerializationMapping:listSerializationMapping forClass:[List class]];

(That gives the above error). I know there is a pretty straightforward way to do this, but none of the examples have this code, and all the documentation seems out of date... Do you have to send the info as POST parameters as well? Help would be appreciated, Thank you!

Update
This is the server response - it works, but it appears that the parameters are a bit messed up? (The title I put in was: "Made from the iPhone 2!")

Started POST "/lists" for 129.21.86.32 at 2011-12-07 09:34:43 -0500
  Processing by ListsController#create as JSON
  Parameters: {"id"=>0, "title"=>"Made from the iPhone 2!", "list"=>{"id"=>0, "title"=>"Made from the iPhone 2!"}}
WARNING: Can't verify CSRF token authenticity
WARNING: Can't mass-assign protected attributes: id
   (0.3ms)  BEGIN
  SQL (0.9ms)  INSERT INTO "lists" ("created_at", "title", "updated_at") VALUES ($1, $2, $3) RETURNING "id"  [["created_at", Wed, 07 Dec 2011 14:34:43 UTC +00:00], ["title", "Made from the iPhone 2!"], ["updated_at", Wed, 07 Dec 2011 14:34:43 UTC +00:00]]
   (16.4ms)  COMMIT
Completed 201 Created in 77ms (Views: 1.8ms | ActiveRecord: 21.9ms)
Was it helpful?

Solution

I think the inverseMapping selector should be enough to make a serialization mapping

RKManagedObjectMapping *listMapping = [RKManagedObjectMapping mappingForClass:[List class]];
listMapping.primaryKeyAttribute = @"listID";

[listMapping mapAttributes:@"title", nil];
[listMapping mapKeyPath:@"id" toAttribute:@"listID"];
[manager.mappingProvider setMapping:listMapping forKeyPath:@"list"];
//this should be enough
[manager.mappingProvider setSerializationMapping:[listMapping inverseMapping] forClass:[List class]];

Edit:

according to our chat conversation, the warnings produced by RestKit were caused by the fact that the server response was lacking the root KeyPath (returned as naked array). To solve the problem we need to tell RestKit to use specific mapping to map the response:

mapping = [[[RKObjectManager sharedManager] mappingProvider] mappingForKeyPath:@"list"];
[[RKObjectManager sharedManager] postObject:newList mapResponseWith:mapping delegate:self];

OTHER TIPS

This is from the RestKit docs. There is a convenience method that sets both mapping and serialization mapping

[[RKObjectManager sharedManager].mappingProvider registerMapping:mapping withRootKeyPath:@"person"];

This will call setMapping:forKeyPath: for you, then generate a serialization mapping and set the root keyPath as well.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top