Rails 4.x嵌套表单中的jQuery文件上传

时间:2015-03-15 16:55:45

标签: javascript jquery ruby-on-rails

我有一个Horse模型和一个Photo模型。我正在使用jQuery文件上传调整大小(客户端)图像并直接保存在Amazon s3上,因为我使用的是Heroku。

我见过类似的其他问题,使用了载波,回形针或者非常古老的问题。我不确定你为什么要使用carrierwave / paperclip,但我认为根据heroku的说法,我不想让图像撞到服务器上,可能导致超时。

Heroku recommends使用jQuery文件上传并显示js附加新文件输入,其中包含图像链接的值(从amazon s3返回)。单独保存照片时,我有此工作。我现在想让它以嵌套的形式为Horse工作但是js没有找到输入(因为它还不存在因为它嵌套我认为)。

我正在使用Cocoon来嵌套表单(我对任何可以更好地工作的东西开放)。我对javascript / jQuery不太熟悉,但据我所知,Cocoon'隐藏'嵌套元素,直到我点击通过add_association添加它。

haml查看代码:

= link_to_add_association 'add photo', f, :photos

html来源,然后点击'添加照片'

<div class='links'>
<a class="btn btn-default btn-sm add_fields" data-association-insertion-method="after" data-association="photo" data-associations="photos" data-association-insertion-template="&lt;div class=&#39;nested-fields&#39;&gt;
  &lt;fieldset class=&quot;inputs&quot;&gt;&lt;ol&gt;&lt;input type=&quot;file&quot; name=&quot;horse[photos_attributes][new_photos][url]&quot; id=&quot;horse_photos_attributes_new_photos_url&quot; /&gt;
  &lt;input type=&quot;hidden&quot; name=&quot;horse[photos_attributes][new_photos][_destroy]&quot; id=&quot;horse_photos_attributes_new_photos__destroy&quot; value=&quot;false&quot; /&gt;&lt;a class=&quot;remove_fields dynamic&quot; href=&quot;#&quot;&gt;remove photo&lt;/a&gt;
  &lt;/ol&gt;&lt;/fieldset&gt;
&lt;/div&gt;
" href="#">add photo</a>

如何使用此输入以及如何在正确添加文件时处理多个文件?

我目前上传的js:

$(function() {
  if ($('#new_horse').length > 0) {
    $.get( "/presign", function( s3params ) {

  $('.direct-upload').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.fileupload({
      fileInput:       fileInput,
      url:             "http://" + s3params.url.host,
      type:            'POST',
      autoUpload:       true,
      formData:         s3params.fields,
      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
      disableImageResize: false,
      imageQuality: 0.5,
      disableImageResize: /Android(?!.*Chrome)|Opera/ 
        .test(window.navigator && navigator.userAgent),
      imageMaxWidth: 500,
      imageMaxHeight: 1000,
      imageOrientation: true,  //auto rotates images
      acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i, //I added this to jquery.fileupload-validate: alert('Must Be JPG GIF or PNG Image')
      replaceFileInput: false,
      progressall: function (e, data) {
        var progress = parseInt(data.loaded / data.total * 100, 10);
        progressBar.css('width', progress + '%')
      },
      start: function (e) {
        submitButton.prop('disabled', true);
        fileInput.after(barContainer);
        progressBar.
          css('background', 'green').
          css('display', 'block').
          css('width', '0%').
          text("Loading...");
      },
      done: function(e, data) {
        submitButton.prop('disabled', false);
        progressBar.text("Pre-uploading done... Please Save or Cancel");

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

        // remove first input to prevent phantom upload delay
       fileInput.remove();

        // create new hidden input with image url
        var input = $("<input />", { type:'hidden', name: fileInput.attr('name'), value: url })
        var imgPreview =  '<img src="' + url + '">';

        form.append(input);
        form.append(imgPreview);
      },
      fail: function(e, data) {
        submitButton.prop('disabled', false);

        progressBar.
          css("background", "red").
          text("Failed");
      }
    });
  });

    }, 'json');
  }
});

1 个答案:

答案 0 :(得分:1)

我想我应该先看一下cocoon文档: http://www.rubydoc.info/gems/cocoon#Callbacks__upon_insert_and_remove_of_items_ http://www.rubydoc.info/gems/cocoon/1.2.6

我将upload.js文件修改为以下内容,它完美地适用于嵌套表单中的多个文件:

// added for file uploading
// https://devcenter.heroku.com/articles/direct-to-s3-image-uploads-in-rails
// Get our s3params from our endpoint

$(document).on('ready page:load', function () {
  $('.direct-upload')
    .on('cocoon:after-insert', function(e, photo) {
      console.log('inside cocoon image function');

      $.get( "/presign", function( s3params ) {
         $('.direct-upload').find("input:file").each(function(i, elem) {
           console.log('inside nested-fields photo input form');

          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.fileupload({
            fileInput:       fileInput,
            url:             "http://" + s3params.url.host,
            type:            'POST',
            autoUpload:       true,
            formData:         s3params.fields,
            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
            disableImageResize: false,
            imageQuality: 0.5,
            disableImageResize: /Android(?!.*Chrome)|Opera/ 
              .test(window.navigator && navigator.userAgent),
            imageMaxWidth: 500,
            imageMaxHeight: 1000,
            imageOrientation: true,  //auto rotates images
            acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i, //I added this to jquery.fileupload-validate: alert('Must Be JPG GIF or PNG Image')
            replaceFileInput: false,
            previewMaxWidth: 100,
            previewMaxHeight: 100,
            previewCrop: true,
            progressall: function (e, data) {
              var progress = parseInt(data.loaded / data.total * 100, 10);
              progressBar.css('width', progress + '%')
            },
           start: function (e) {
              submitButton.prop('disabled', true);
              fileInput.after(barContainer);
              progressBar.
              css('background', 'green').
              css('display', 'block').
              css('width', '0%').
              text("Loading...");
           },
           done: function(e, data) {
              submitButton.prop('disabled', false);
              progressBar.text("Photo Uploaded");

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

              // remove first input to prevent phantom upload delay
             fileInput.remove();

              // create new hidden input with image url
              var input = $("<input />", { type:'hidden', name: fileInput.attr('name'), value: url })
              var imgPreview =  '<img src="' + url + '">';

              form.append(input);
              form.append(imgPreview);
            },
            fail: function(e, data) {
              submitButton.prop('disabled', false);
              progressBar.
              css("background", "red").
              text("Failed");
            }

    }, 'json'); //fileupload
   }); //each file 

 }); //presign call

});    // function cocoon
});    // page ready  

我猜谷歌和一个记录良好的宝石可以在短期内取代JS的知识:-)我相信它并不紧张,因为它可以提供任何改进。