Pregunta

I have a Rails app with a Business model object with a count of visits. I have an iOS client that interacts with this Rails app using AFNetworking 2.0, and when a user taps a business in the app, it sends a PATCH to the Rails app, incrementing visits for that business. However, I'm getting a status code 422 "Unprocessable Entity" error back from the server, and the business's visits count on the server is not getting incremented.

AFHTTPSessionManager - iOS

- (NSURLSessionDataTask *)visitVenue:(NOTVenue *)venue withCompletionBlock:(void (^)(BOOL success))completionBlock {
NSURLSessionDataTask *dataTask = [self PATCH:[NSString stringWithFormat:@"businesses/%li.json", (long)[venue.identifier integerValue]]
                                  parameters:@{@"visits": @(venue.numberOfVisits + 1)}
                                     success:^(NSURLSessionDataTask *task, id responseObject) {
                                         NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)task.response;
                                         
                                         if (httpResponse.statusCode == 200) {
                                             dispatch_async(dispatch_get_main_queue(), ^{
                                                 completionBlock(YES);
                                             });
                                         } else {
                                             dispatch_async(dispatch_get_main_queue(), ^{
                                                 completionBlock(NO);
                                             });
                                         }
                                     }
                                     failure:^(NSURLSessionDataTask *task, NSError *error) {
                                         dispatch_async(dispatch_get_main_queue(), ^{
                                             completionBlock(NO);
                                         });
                                     }];

return dataTask;

}

Businesses Controller - Rails

# PATCH/PUT /businesses/1
# PATCH/PUT /businesses/1.json
def update
  respond_to do |format|
    if @business.update(business_params)
      format.html { redirect_to @business, notice: 'Business was successfully updated.' }
      format.json { head :no_content }
    else
      format.html { render action: 'edit' }
      format.json { render json: @business.errors, status: :unprocessable_entity }
    end
  end
end
¿Fue útil?

Solución 2

The correct solution for this was found on the Rails API site. Here is the code:

class ApplicationController < ActionController::Base
  protect_from_forgery
  skip_before_action :verify_authenticity_token, if: :json_request?

  protected

  def json_request?
    request.format.json?
  end
end

Otros consejos

If the web API allows to increment a model objects's counter, it should have a dedicated "method" for that.

Generally, an Increment Counter feature won't work reliable if the client itself increments the counter performed on a local copy which it received before from the server and then tries to update the server's value via composing a PATCH request where the client sends just the value local_counter+1. In the meantime, other clients could have the same idea, in which case the counter value on the server would be become corrupt. Also, one could update the counter on the server to any value - which is certainly not desired.

This has the consequence, that the counter variable MUST be read only for the clients.

There must be other means (defined by the web API) where a client can accomplish this. For example, a REST API would define a particular "resource" (e.g. some sort of "ticket" or "reservation") which a client can create. The creation of this resource will have the effect of incrementing the counter variable on the server.

Edit

If you are testing a web API, the command line tool curl is invaluable:

Test the PATCH request:

In Terminal.app enter this command:

curl -sSv -X PATCH \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"email”:”jappleseed@mail.com"}' \
    http://localhost:3000/api/v1/users/123 \
    | python -m json.tool
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top