Rails 5:如何防止来自 jQuery 的多次提交

Posted

技术标签:

【中文标题】Rails 5:如何防止来自 jQuery 的多次提交【英文标题】:Rails 5 : How to prevent multiple submission from jQuery 【发布时间】:2018-09-11 19:26:02 【问题描述】:

我是编码初学者。

我正在 Rails 5 上开发我的应用程序,并让用户使用 blueimp/jQuery-File-Upload 裁剪图像并将其从客户端直接上传到 AWS s3。

当用户重新选择要裁剪和上传的图像时,我遇到了问题。 这种重新选择会导致向 Rails 提交多个表单,最终会创建与重新选择相同数量的帖子...

我想知道如何防止这种多次提交。

我的 javascript 代码是这样的;

$(function() 
  $('.directUpload').find("input:file").each(function(i, elem) 
    var fileInput    = $(elem);
    var form         = $(fileInput.parents('form:first'));
    var submitButton = form.find('input[type="submit"]');
    var progressBar  = $("<div class='bar'></div>");
    var barContainer = $("<div class='progress'></div>").append(progressBar);
    fileInput.after(barContainer);
    fileInput.fileupload(
    fileInput:       fileInput,
    url:             form.data('url'),
    type:            'POST',
    autoUpload:       false,
    formData:         form.data('form-data'),
    paramName:        'file', // S3 does not like nested name fields i.e. name="user[avatar_url]"
    dataType:         'XML',  // S3 returns XML if success_action_status is set to 201
    replaceFileInput: false,
    acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i,
    //trying to limit the number of files, but none of them works...
    maxNumberOfFiles: 1,
    sequentialUploads: true,
    limitMultiFileUploads:1,
    limitConcurrentUploads: 1,

    add: function(e, data)
      if (data.files && data.files[0]) 
        var reader = new FileReader();
        reader.onload = function(e) 
          $('.preview').empty();
          $('.preview').append($('<img>').attr(// insert preview image
            src: e.target.result,
            id: "crop_img",
            title: data.files[0].name
          ));
          $('#crop_img').cropper() // initialize cropper on preview image
         ;
       reader.readAsDataURL(data.files[0]);
       // $('#clear').show();
      ;

      // tried to clear the form and file input when re-selection occurs, however, it doesn't work either...
      // $('#clear').click(function() 
      //     $('#image').val('');
      //     $('.preview').empty();
      //     $('form').reset();
      //     $(this).hide();
      //   );

      submitButton.on('click', function()
      $('form').submit(function()
        return false;
        );
       $('#crop_img').cropper('getCroppedCanvas').toBlob(function (blob)
          data.files[0] = new File([blob], data.files[0].name);
          data.originalFiles[0] = data.files[0];
          data.submit();
        )
     );
    ,

   ...
    
    done: function(e, data) 

      // extract key and generate URL from response
      var key   = $(data.jqXHR.responseXML).find("Key").text();
      var url   = '//' + form.data('host') + '/' + key;

      // create hidden field
      var input = $("<input />",  type:'hidden', name: fileInput.attr('name'), value: url )
      form.append(input);

      //delete submit event which is false
      $('form').off('submit');
      //and submit again
      $('.directUpload').submit();
    
    ...
    );
  );
);

【问题讨论】:

【参考方案1】:

我认为这是因为每次调用add 时都会调用以下代码:

submitButton.on('click', function()
  $('form').submit(function()
    return false;
    );
   $('#crop_img').cropper('getCroppedCanvas').toBlob(function (blob)
      data.files[0] = new File([blob], data.files[0].name);
      data.originalFiles[0] = data.files[0];
      data.submit();
    )
 );

我不确定您的代码是如何工作的。因此,一种解决方案是将代码更新为:

// outside add function:
var lastData = null;

submitButton.on('click', function()
  $('form').submit(function()
    return false;
    );
   $('#crop_img').cropper('getCroppedCanvas').toBlob(function (blob)
      lastData.files[0] = new File([blob], data.files[0].name);
      lastData.originalFiles[0] = lastData.files[0];
      lastData.submit();
    )
 );

 // In add function
 lastData = data;

PS:lastData 是一种快速的解决方法,但我认为它不能正常工作。

$(function() 
  $('.directUpload').find("input:file").each(function(i, elem) 
    var fileInput    = $(elem);
    var form         = $(fileInput.parents('form:first'));
    var submitButton = form.find('input[type="submit"]');
    var progressBar  = $("<div class='bar'></div>");
    var barContainer = $("<div class='progress'></div>").append(progressBar);

    var lastData = null;
    submitButton.on('click', function()
      $('form').submit(function()
        return false;
      );
     $('#crop_img').cropper('getCroppedCanvas').toBlob(function (blob)
        lastData.files[0] = new File([blob], data.files[0].name);
        lastData.originalFiles[0] = lastData.files[0];
        lastData.submit();
      )
    );

    fileInput.after(barContainer);
    fileInput.fileupload(
    fileInput:       fileInput,
    url:             form.data('url'),
    type:            'POST',
    autoUpload:       false,
    formData:         form.data('form-data'),
    paramName:        'file', // S3 does not like nested name fields i.e. name="user[avatar_url]"
    dataType:         'XML',  // S3 returns XML if success_action_status is set to 201
    replaceFileInput: false,
    acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i,
    //trying to limit the number of files, but none of them works...
    maxNumberOfFiles: 1,
    sequentialUploads: true,
    limitMultiFileUploads:1,
    limitConcurrentUploads: 1,

    add: function(e, data)
      if (data.files && data.files[0]) 
        var reader = new FileReader();
        reader.onload = function(e) 
          $('.preview').empty();
          $('.preview').append($('<img>').attr(// insert preview image
            src: e.target.result,
            id: "crop_img",
            title: data.files[0].name
          ));
          $('#crop_img').cropper() // initialize cropper on preview image
         ;
       reader.readAsDataURL(data.files[0]);
       // $('#clear').show();
      ;

      // tried to clear the form and file input when re-selection occurs, however, it doesn't work either...
      // $('#clear').click(function() 
      //     $('#image').val('');
      //     $('.preview').empty();
      //     $('form').reset();
      //     $(this).hide();
      //   );

      lastData = data;
    ,

   ...
    
    done: function(e, data) 

      // extract key and generate URL from response
      var key   = $(data.jqXHR.responseXML).find("Key").text();
      var url   = '//' + form.data('host') + '/' + key;

      // create hidden field
      var input = $("<input />",  type:'hidden', name: fileInput.attr('name'), value: url )
      form.append(input);

      //delete submit event which is false
      $('form').off('submit');
      //and submit again
      $('.directUpload').submit();
    
    ...
    );
  );
);

【讨论】:

以上是关于Rails 5:如何防止来自 jQuery 的多次提交的主要内容,如果未能解决你的问题,请参考以下文章

jquery ajax如何防止多次提交

javascript 如何防止多次触发hover事件

由于rails资产,jQuery事件多次触发?

Rails 4 + Turbolinks + JQuery Turbolinks + Coffeescript:事件被多次触发

jQuery-turbolinks - link_to 确认:在 Rails 中多次弹出

如何防止表单在 5 分钟内多次提交?