rails: form_with doesn't post remote forms with empty file input on Safari

When using form_with with a single file_field (using the form helper), the form will not submit on Safari for OSX if no file was chosen. Switching to “local: true”, solves the problem.

Steps to reproduce

1 - Create a form using form_with; 2 - Add a single file input field using the file_field helper; 3 - Without selecting a file, click submit.

Expected behavior

Form is submitted in all browsers

Actual behavior

In Safari the form isn’t submitted. In Chrome, Android and Safari iOS the form is submitted.

System configuration

Rails version: 5.2.0.rc2 Ruby version: 2.4.3 and 2.5.0 OSX version: 10.13.4 Safari version: 11.1 (13605.1.33.1.2)

Relevant Code

<%= form_with(scope: :photo, url: photos_path, method: :post) do |f| %>
  <%= f.file_field :file, accept: "image/gif, image/jpg, image/jpeg, image/png" %>
  <%= f.submit "Save" %>
<% end %>

Demo Repository

https://github.com/brenogazzola/turbolinks-bug-demo

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 1
  • Comments: 16 (10 by maintainers)

Commits related to this issue

Most upvoted comments

Created (updated) workaround snippet: https://gist.github.com/ypresto/b4715b06230d4014a90eaacc3445158f

// iOS 11.3 Safari / macOS Safari 11.1 empty <input type="file"> XHR bug workaround.
// Replace empty File object with equivalent Blob in FormData, keeping its order, before sending it to server.
// Should work with IE10 and all other modern browsers.
// Because useragent value can be customized by WebView or etc., applying workaround code for all browsers.
// https://stackoverflow.com/questions/49614091/safari-11-1-ajax-xhr-form-submission-fails-when-inputtype-file-is-empty
// https://github.com/rails/rails/issues/32440
document.addEventListener('ajax:beforeSend', function(e) {
  var formData = e.detail[1].data
  if (!(formData instanceof window.FormData)) return
  if (!formData.keys) return // unsupported browser
  var newFormData = new window.FormData()
  Array.from(formData.entries()).forEach(function(entry) {
    var value = entry[1]
    if (value instanceof window.File && value.name === '' && value.size === 0) {
      newFormData.append(entry[0], new window.Blob([]), '')
    } else {
      newFormData.append(entry[0], value)
    }
  })
  e.detail[1].data = newFormData
})

See here for detail: https://stackoverflow.com/a/49827426/1474113

Hi,

I just came across with a similar problem and found this SO. Probably it’s not a bug in Rails? Hope it would be of your help. https://stackoverflow.com/questions/49614091/safari-11-1-ajax-xhr-form-submission-fails-when-inputtype-file-is-empty

Unfortunately not. I thought of capturing a form submit event and removing the empty file input, but I couldn’t get the submit it to trigger (maybe a Turbolinks thing?). Capturing clicks on the submit button wouldn’t for me either since I sometimes trigger the submit programatically and didn’t want to refactor.

Still, if you want to try the submit button method, the closest I got was the code below (I’m not using jQuery, that’s why I’m adding the event delegation code I use below:

this.App || (this.App = {});
this.App.util = (function () {
    function delegate(event, selector, callback) {
        document.addEventListener(event, function (e) {
            if (e.target.matches(selector)) {
                e.stopPropagation();

                self = e.srcElement || e.target;
                callback(e);
            }
        });
    }

    return {
        delegate: delegate,
    };
})();

App.util.delegate("click", "input[type='submit']", function(){
    var file_input = document.querySelector("input[type=file]");
    if (file_input.files.length === 0) file_input.parentNode.removeChild(file_input);
});