We\'re using Ruby 2.1.2, Rails 3.2.19 with JQuery 1.11, asset pipeline is not being used (so not using JQuery-ujs, but are using relevant rails.js explicitly). For most user
This was finally solved and I'm posting what happened in case it's helpful to others.
Summary The original code contained an ajaxSubmit (via jquery.form plugin) in the JS which submitted a form (as a POST) with multipart/form-data encoding (so far so good). The rails controller handling the submission processed the data normally and then redirected to a second href (as a GET). The browser (perhaps still processing through the jquery.form plugin before returning to it's success
callback handler) received the redirect and retained the multipart/form-data encoding type. When rack received the GET with multipart encoding still specified, it balked because there was no multipart data to parse.
Sorry, much of this wasn't in evidence in my OP. And it's not clear to me why this worked under an older version of JQuery and the JQuery.form plugin or why it sometimes succeeded under the new JQuery/JQuery.form.
Solution Refactored the controller to no longer redirect, but rather return a URL (as a text render) for the success
callback handler of the original ajaxSubmit. The success
handler now then does an AJAX GET on the returned URL thereby leaving the workflow intact but avoiding any multipart encoding on the GET request.
tl;dr :
Before the code was ever changed, we had a path involving Jquery.form that went something like this (code example is not meant to be executable, but just as an illustration):
Ruby view (in HAML for form being submitted):
= form_for @someObject, html: {:multipart => true, :class => "someformclass"} do |f|
= f.error_messages
= hidden_field_tag :submitted, true
=# some more fields
%p.submits
= f.submit "Submit", class: "submit"
Ruby controller:
class OurController < ApplicationController
layout false
before_filter :authenticate_user!
# some other actions
def create
# some processing
someObject.save
redirect_to new_feedback_path, :method => :get, :notice => "notice text", status: 303
end
# some other actions
end
JS:
$(document).on('click', '.someformclass .submit', function() {
...
$(this).parents('form').ajaxSubmit({ // uses jquery.form
...
beforeSubmit: function(someargs) {
... blah blah
},
success: function(responseText) {
// ... code to display flash message
if (typeof(window.history.pushState) == 'function') {
window.history.pushState('html', 'sometext', $.cookie('current_url'));
matchFiltersClass(window.location.pathname);
} else {
window.location.hash = '#!' + $.cookie('current_path');
matchFiltersClass($.cookie('current_path'));
}
$('#main_content').html(responseText);
}
});
return false;
});
This was refactored as follows (again, just an illustration):
Ruby view (in HAML for form being submitted): unchanged
Ruby controller:
class OurController < ApplicationController
layout false
before_filter :authenticate_user!
# some other actions
def create
# some processing
someObject.save
flash[:notice] = 'notice text' # NEW LINE
render text: new_feedback path, status: accepted #CHANGED LINE
end
# some other actions
end
JS:
$(document).on('click', '.someformclass .submit', function() {
...
$(this).parents('form').ajaxSubmit({ // uses jquery.form
...
beforeSubmit: function(someargs) {
... blah blah
},
success: function(responseText) {
// ... code to display flash message
$.get(responseText, function(data) { // NEW LINE
if (typeof(window.history.pushState) == 'function') {
window.history.pushState('html', 'sometext', $.cookie('current_url'));
matchFiltersClass(window.location.pathname);
} else {
window.location.hash = '#!' + $.cookie('current_path');
matchFiltersClass($.cookie('current_path'));
}
$('#main_content').html(responseText);
}); // NEW LINE
}
});
return false;
});
This solution was found with some help with a local developer (thanks, Dan Axtman!) and not without a fair amount of time in monkey-patched logging in Rack (thanks, Isaac Betesh!). At least I learned something about Rack and monkey patching in the process...