jquery doesn't call success method on $.ajax for rails standard REST DELETE answer

JqueryRuby on-RailsRest

Jquery Problem Overview


May be such problem is not new, but I didn't find anything similar. I have such jQuery code:

$.ajax({ 
  url : ('/people/'+id), 
  type : 'DELETE', 
  dataType : 'json', 
  success : function(e) {
    table.getItems(currentPage);
  }
});

My Rails controller looks like this:

def destroy
    @person = Person.find(params[:id])
    @person.destroy

    respond_to do |format|
      format.html { redirect_to(people_url) }
      format.json  { render :json => @person, :status => :ok }
    end
end

This is working.

But when I use the following (as generated by standard), the success callback doesn't get called:

def destroy
    @person = Person.find(params[:id])
    @person.destroy

    respond_to do |format|
      format.html { redirect_to(people_url) }
      format.json  { head :ok }
    end
end

Tested under rails 3.0.3, jQuery 1.4.2 and Firefox 3.6.13.
Firebug says, that query is fired and returns 200 OK in both cases, item is deleted in both cases too. But in second case the callback is not called.

Is there a significant difference in REST, and is there a way to utilize jQuery by using the scaffolded controller?

Jquery Solutions


Solution 1 - Jquery

I have run across this a few times and the answer is deceptively simple.

You are using dataType : 'json' in your $.ajax call, so jQuery is expecting a JSON response. With head :ok Rails returns a response containing a single space (http://github.com/rails/rails/issues/1742), which is not accepted by jQuery as valid JSON.

So if you really expect to get either an error or a bare 200 OK header, just set dataType : 'html' in your request and it should work (if you don't set dataType, jQuery will try to guess at what the type is based on response headers, etc., and could still guess json, in which case you'd still have this problem). If you actually expect to get JSON back, instead of using head :ok render something valid with JSON (see comments) or just use head :no_content as suggested by @Waseem

Solution 2 - Jquery

GearHead is correct, except that the jQuery parser is actually smart enough now to treat an empty string response as null and not attempt to parse it.

However if you have calls that will sometimes receive json and sometimes receive a head response, and you do not have access to the server or do not want to change all your head calls, you can do this alternate solution:

The problem is that Rails sends a single space as an empty response when you use head (see here: https://stackoverflow.com/questions/3351247/how-to-return-truly-empty-body-in-rails-i-e-content-length-0)

The relevant parts of the jQuery parseJSON function look like this at the time of this writing:

parseJSON: function( data ) {
	if ( typeof data !== "string" || !data ) {
		return null;
	}

	// Make sure leading/trailing whitespace is removed (IE can't handle it)
	data = jQuery.trim( data );

	// Attempt to parse using the native JSON parser first
	if ( window.JSON && window.JSON.parse ) {
		return window.JSON.parse( data );
	}

As you can see, jQuery is testing whether the data is an empty string before trimming it. It then tries to JSON.parse("") which you can see in your console results in an error, triggering the ajax error callback via a catch statement.

There is a simple fix. jQuery allows you to use converters when one data type is requested and a different one is returned. See here for more details: http://api.jquery.com/extending-ajax/

Since the rails head response renders as text, you can simply define a text to json converter that will trim the response prior to attempting to parse it. Just add this snippet:

// deal with rails ' ' empty response
jQuery.ajaxSetup({
  converters: {
    "text json": function (response) {
      jQuery.parseJSON($.trim(response))
    }
  }
})

Solution 3 - Jquery

This is sometimes caused by an old version of the jQuery Validate Plugin. If you are using this plugin, this sometimes leads to this issue. There is an update that fixes this, if it applies to your case.

Alternatively, you can probably figure out what's going wrong by setting up an error handler via:

$.ajaxSetup() or $.ajaxError()

This will probably return a parse error. The newer versions of jQuery are notorious for being very strict with regards to JSON parsing.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionsandrewView Question on Stackoverflow
Solution 1 - JquerymtjhaxView Answer on Stackoverflow
Solution 2 - JqueryNeil SarkarView Answer on Stackoverflow
Solution 3 - JqueryFareesh VijayarangamView Answer on Stackoverflow