Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

jquery fileupload with nested attributes #75

Open
sangamgupta85 opened this issue Jul 19, 2015 · 4 comments
Open

jquery fileupload with nested attributes #75

sangamgupta85 opened this issue Jul 19, 2015 · 4 comments
Labels

Comments

@sangamgupta85
Copy link

Hi there

Can someone guide me about uploading files using carrierwave with nested attributes and jquery-fileupload-rails plugin.

Basically my requirement is I have a Package that has many Images. How can I create a package with package details along with adding multiple images with nested form using jquery fileupload plugin.

When I create a package with multiple images using nested form, it takes too much time to process the request specially if images are of bigger size around 6-7 MBs. I am using and passenger and nginx in my production server.

Thanks
Sangam Gupta

@felixbuenemann
Copy link
Collaborator

jQuery File Upload works asynchronously, which means it cannot work with nested forms. Your best bet is to create the records you want to attach your images to first, so you can associate to them in the controller.

Or you can upload the images to a non-nested route and associate them later. The latter case requires you to send some sort of client generated reference, like a uuid with the record that you can then also submit in your nested form and you would need to have some kind of cleanup task to remove abandoned uploads.

Oh and another variation would be to submit your nested form using ajax, add your file upload outside that form and trigger the upload using the jquery fileupload js api, if your form submit was successful.

@sangamgupta85
Copy link
Author

Thanks for suggestions. Could you please let me know which option would be the best for my current implementation using jquery-fileupload-rails plugin.

         <%= nested_form_for @package , :html => {multipart: true} do |f| %>
              <%= f.fields_for :pictures do |p| %>
                  <%= p.file_field :image %>
                  <%= p.link_to_remove "Remove this image" %>
              <%end%>
            <%= f.link_to_add "Add image" %>

            <%=f.submit "Submit" %>
         <%end%>

Any example with code snippet would be great.

@ssilvius
Copy link

So this can be done... with some twisting.

I changed my object names to make them more generic and easier to understand. Parent is the model that you'll be nesting into. Link is the child object.

The Form (haml):

    = form_for @parent, :remote => true do |f|
      = f.fields_for :links do |img|
        .form-group.hidden
          = img.file_field :image
        .target
          #dropzone.fade drop files here  
        .progress-wrapper
          %p 
            Bitrate: 
            %span.bitrate
          .progress
            .progress-bar{:role => "progressbar"}
              0%

In the parent controller you need to setup the params, add

links_attributes: [:image]

to the param.require(:parent).permit()

Also in the parent controller you need to build an "link" object so it's ready in the view.

def new
  @parent = Parent.new
  @parent.links.build
end

In the parent model

has_many :links,   :dependent => :destroy 
accepts_nested_attributes_for :links

and of course add to the links model

belongs_to :parent

and the javascript, really standard

$(document).ready(function() {
    var multiple_photos_form = $('.edit_parent');
    var wrapper = multiple_photos_form.find('.progress-wrapper');
    var bitrate = wrapper.find('.bitrate');
    var progress_bar = wrapper.find('.progress-bar');

    multiple_photos_form.fileupload({
      dataType: 'script',
      dropZone: $('#dropzone'),
      add: function (e, data) {
        types = /(\.|\/)(gif|jpe?g|png|mov|mpeg|mpeg4|avi)$/i;
        file = data.files[0];
        if (types.test(file.type) || types.test(file.name)) {
          data.submit();
        }
        else { alert(file.name + " is not a image or movie file."); }
      }
    });
    multiple_photos_form.on('fileuploadstart', function() {
      wrapper.show();
    });
    multiple_photos_form.on('fileuploaddone', function() {
      wrapper.hide();
      progress_bar.width(0);
    });

    multiple_photos_form.on('fileuploadprogressall', function (e, data) {
      bitrate.text((data.bitrate / 1024).toFixed(2) + 'Kb/s');
      var progress = parseInt(data.loaded / data.total * 100, 10);
      progress_bar.css('width', progress + '%').text(progress + '%');
    });
    $(document).bind('dragover', function (e) {
      var dropZone = $('#dropzone'),
              timeout = window.dropZoneTimeout;
      if (!timeout) {
        dropZone.addClass('in');
      } else {
        clearTimeout(timeout);
      }
      var found = false,
              node = e.target;
      do {
        if (node === dropZone[0]) {
          found = true;
          break;
        }
        node = node.parentNode;
      } while (node != null);
      if (found) {
        dropZone.addClass('hover');
      } else {
        dropZone.removeClass('hover');
      }
      window.dropZoneTimeout = setTimeout(function () {
        window.dropZoneTimeout = null;
        dropZone.removeClass('in hover');
      }, 100);
    });
});

Hope this helps.

@sangamgupta85
Copy link
Author

@ssilvius thanks for the code snippet but it seems it's not working as expected.

Here is repo - https://github.com/sangamgupta85/file-upload

Could you please advise?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants