Reputation: 45
I am building a rails-backed ios app that uses AFNetworking to POST content to a server. A user can upload a photo with a comment - and this works. I also want to have the option to let a user upload just text- this is where I am having trouble. I have one method for saving a photo and text, and another method for saving just text. The save photo method works, but the save text method creates a post but the text is null. The save photo implementation is like this:
- (void)savePhotoAtLocation:(CLLocation *)location
withBlock:(void (^)(CGFloat))progressBlock completion:(void (^)(BOOL, NSError *))completionBlock {
if (!self.content) self.content = @"";
NSDictionary *params = @{
@"post[content]" : self.content,
@"post[lat]": @(location.coordinate.latitude),
@"post[lng]": @(location.coordinate.longitude)
};
NSURLRequest *postRequest = [[APIClient sharedClient] multipartFormRequestWithMethod:@"POST" path:@"/posts" parameters:params
constructingBodyWithBlock:^(id<AFMultipartFormData> formData)
{
[formData appendPartWithFileData:self.photoData
name:@"post[photo]"
fileName:@""
mimeType:@"image/png"];
}];
AFHTTPRequestOperation *operation = [[AFJSONRequestOperation alloc] initWithRequest:postRequest];
This method only works when there is photoData- if you don't have photoData, the app crashes. So I am wondering what is the equivalent to a multipartFormRequest- that lets you only include a string? This is what I have right now- which creates a post- but returns content: as well as the lat/lng params which should be returned with the current location. This is defined in the post model
- (void)savePostAtLocation:(CLLocation *)location
withBlock:(void (^)(CGFloat progress))progressBlock completion:(void (^)(BOOL success, NSError *error))completionBlock {
if (!self.content) self.content = @"";
NSDictionary *params = @{
@"post[content]" : self.content,
@"post[lat]" : @(location.coordinate.latitude),
@"post[lng]" : @(location.coordinate.longitude)
};
NSURLRequest *postRequest = [[APIClient sharedClient]requestWithMethod:@"POST" path:@"/posts" parameters:params];
AFHTTPRequestOperation *operation = [[AFJSONRequestOperation alloc] initWithRequest:postRequest];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
if (operation.response.statusCode == 200 || operation.response.statusCode == 201) {
NSLog(@"Created, %@", responseObject);
NSDictionary *updatedPost = [responseObject objectForKey:@"post"];
[self updateFromJSON:updatedPost];
[self notifyCreated];
completionBlock(YES, nil);
} else {
completionBlock(NO, nil);
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
completionBlock(NO, error);
}];
[[APIClient sharedClient] enqueueHTTPRequestOperation:operation];
}
And in the AddPostViewController save calls this:
- (void)save:(id)sender
{
CLLocationManager * locationManager = [[CLLocationManager alloc] init];
self.locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
self.locationManager.distanceFilter = 80.0f;
[locationManager startUpdatingLocation];
[self getLocation];
CLLocation * location = [locationManager location];
Post *post = [[Post alloc] init];
post.content = self.contentTextField.text;
[self.view endEditing:YES];
ProgressView *progressView = [ProgressView presentInWindow:self.view.window];
if (location) {
[post savePostAtLocation:self.locationManager.location withBlock:^(CGFloat progress) {
[progressView setProgress:progress];
} completion:^(BOOL success, NSError *error) {
[progressView dismiss];
if (success) {
[self.navigationController popViewControllerAnimated:YES];
} else {
NSLog(@"ERROR: %@", error);
}
}];
} else {
NSLog(@"No Location");
}
}
Here is the log after a post is created. As you can see the attributes are null- and shouldn't be.
Created, {
post = {
content = "<null>";
"created_at" = "2013-07-21T18:45:12Z";
id = 13;
lat = "<null>";
lng = "<null>";
success = 1;
}
So the fact that a post is created but the attributes are null makes me think that the problem is simply in the NSURLRequest- and that I am not fully implementing the AFNetworking protocol but I haven't been able to find a way to implement a post request that doesn't entail fileData. How do I make a post request that doesn't append fileData? Any help would be greatly appreciated. Thanks!
Upvotes: 0
Views: 312
Reputation: 45
This is how I got it to work: post.h
+ (void)createNoteAtLocation:(CLLocation *)location
withContent:(NSString *)content
block:(void (^)(Post *post))block;
post.m
+ (void)createNoteAtLocation:(CLLocation *)location
withContent:(NSString *)content
block:(void (^)(Post *post))block
{
NSDictionary *parameters = @{ @"post": @{
@"lat": @(location.coordinate.latitude),
@"lng": @(location.coordinate.longitude),
@"content": content
}
};
[[APIClient sharedClient] postPath:@"/posts" parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
Post *post = [[Post alloc] initWithDictionary:responseObject];
if (block) {
block(post);
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
if (block) {
block(nil);
}
}];
}
And finally in the createPostViewController:
- (void)save:(id)sender
{
CLLocationManager * locationManager = [[CLLocationManager alloc] init];
self.locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
self.locationManager.distanceFilter = 80.0f;
[locationManager startUpdatingLocation];
[self getLocation];
CLLocation * location = [locationManager location];
Post *post = [[Post alloc] init];
post.content = self.contentTextField.text;
[self.view endEditing:YES];
if (location) {
[Post createNoteAtLocation:location withContent:self.contentTextField.text block:^(Post *post) {
NSLog(@"Block: %@", post);
[self.navigationController popViewControllerAnimated:YES];
}];
}
Upvotes: 0
Reputation: 119031
You can copy your existing method but instead of using appendPartWithFileData:name:fileName:mimeType:
to set file data you can convert your parameters to data and add them with appendPartWithFormData:name:
.
Upvotes: 1