Ok, this is a bit involved....
Basically what I have is a Ruby on Rails entity called 'Job'
Here is the Action that receives my Ajax POST request:
-
def update
@job = Job.find params[:id]
if @job.update_attributes params[:job]
respond_to do |format|
format.html do
flash[:notice] = "Job updated successfully. (ID: #{@job.id})"
smart_redirect @job
end
format.json {head :ok}
end
else
respond_to do |format|
format.html do
flash.now[:warning] = AppConfig.messages['submission_invalid']
render :edit
end
format.json {render :json => @job.errors, :status => :unprocessable_entity}
end
end
end
So what this does is tries to update the job from the submitted data, if it can, it responds by either redirecting to the job detail page, or if the requested content-type is json (AKA my Ajax request), it sends a header with status 200. No response text. By sending http status code of 200, I am expecting jQuery to treat this as a successful request.
Here is my jquery:
- jtable = $('section.jobs.open-with-budget table');
jtable.find('td.target-completion-date').each(function(){
$(this).append('<button title="edit" class="action edit">edit</button>');
});
jtable.find('button.edit').click(function(){
tr = $(this).closest('tr');
job_id = tr.attr('data-record-id');
form = $('<form class="formtastic"></form>');
form.append('<fieldset><ol><li>\n\
<label for="job[TargetCompletionDate]">Target Completion Date</label>\n\
<input type="datepicker date" name="job[TargetCompletionDate]" value="' +
$(this).siblings('span.value').text() + '" />\n\
<span class="hint">mm/dd/yyyy</span></li></ol></fieldset>\n\
<input name="_method" type="hidden" value="put" />\n\
<input name="authenticity_token" type="hidden" value="' +
$('#authenticity-token').attr('content') + '" />');
form.appendTo('jtable');
form.dialog({
title: tr.find('td.address').text(),
modal: true,
buttons: {
Ok: function(){
$.loadingBlocksUI = true;
$.ajax({
type: 'POST',
url: '<%= jobs_path %>/' + job_id ,
dataType: 'json',
data: form.serialize(),
success: function(data) {
spn = tr.find('span.value');
spn.text(form.find('input[name*=TargetCompletionDate]').val());
spn.siblings('span.error.flag').remove();
$(this).remove();
},
error: function(xhr) {
if(xhr.status == 422) {
alertValidationErrors(parseErrors(xhr));
} else {
alert('An error occurred while processing the request.');
}
$(this).remove();
}
});
$(this).dialog('close');
},
Cancel: function(){$(this).dialog('close');}
}
});
return false;
});
So to explain:
- jtable is the table of data I am working with
- I want to update one attribute called 'TargetCompletionDate'
- So, I find the cell, inject an edit button.
- When the edit button is clicked, it opens a ui dialog box with a form inside.
- This form only contains one field to update, (TargetCompletionDate)
- -- ANYWAY -- All of this works as described.
- When the user clicks the 'Ok' button, it serializes the form and sends it to the above action.
- If their are validation errors, the action renders those to json, and returns http status 422 (unprocessable_entity)
- if the post action is successful, it simply returns a header response with status 200.
So, what I am assuming is that jquery would call my success callback because of the status code of 200.
but it is not. It calls my error callback. The error callback checks for http code 422. If 422, it will render the validation errors. If anything else, it will alert ''An error occurred while processing the request."
With firebug i have inspected the xhr object inside the error callback and it reports status of 200, thus calling the alert.
I hope this makes sense....