2

Does anyone have advice/examples on getting the jQuery File Upload plugin working with Rails using nested attributes?

My model "has_many" attachments and accept the necessary nested attributes. I would like to get this working with the jQuery File Upload but haven't been able to find any good examples to get me started.

Has anyone achieved something like this and able to give some direction?

Thanks.

2 Answers 2

4

I've succesfuly set it up to work when editing a model with nested attachments.
The same is not possible when creating a new model - at least not currently due to paperclip.

You have to set up some jQuery File Upload options which I found here.

You should call fileUploadUI() on the whole form, and set file input wrapper element as dropZone. You should also set url, fieldName and formData accordingly.

Here's how my JS looks like (simplified):

var $file_upload_form = $("form")
var attachable_id     = $file_upload_form.attr("id").match(/_(\d*)$/)[1]
var attachable_type   = $file_upload_form.attr("id").match(/edit_(\w*)_\d*$/)[1]

$($file_upload_form).fileUploadUI({
    url         : '/admin/attachments',
    fieldName   : "attachment[data]",
    formData    : [
        {
            name  : 'attachment[attachable_id]',
            value : attachable_id
        },
        {
            name  : 'attachment[attachable_type]',
            value : attachable_type
        }
    ],
    dropZone        : $('#attachments_dropzone'),
    uploadTable     : $('#upload_files'),
    downloadTable   : $('#download_files'),
    buildUploadRow  : function (files, index) {
        var file = files[index];
        return $('<tr><td>' + file.name + '<\/td>' +
                        '<td class="file_upload_progress"><div><\/div><\/td>' +
                        '<td class="file_upload_cancel">' +
                        '<button class="ui-state-default ui-corner-all" title="Cancel">' +
                        '<span class="ui-icon ui-icon-cancel">Cancel<\/span>' +
                        '<\/button><\/td><\/tr>');
    },
    buildDownloadRow: function (file) {
        return $('<tr><td><img alt="Photo" width="40" height="40" src="' + file.pic_path + '">' + file.name + '<\/td><\/tr>');
    }
})
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks Mirko - After some digging around I basically came to the same conclusion. I'm able to get the file upload for edits but not for new instances. Definitely the most direct, best, answer. :)
This plugin got a major version bump, so this pastie is no longer relevant. New demo is here: aquantum-demo.appspot.com/file-upload
0

I have coped with this problem and made a demo app to show how to do this.

In short I have two models: item and upload.

item.rb:

has_many :uploads
accepts_nested_attributes_for :uploads, :allow_destroy => true

upload.rb:

belongs_to :item
    has_attached_file :upload, :styles => { :large => "800x800", :medium => "400x400>", :small => "200x200>" }

I added uploads_attributes to item controller.

Now you can add jquery-file-upload form to your view, but there is one problem: it sends each photo in separate requests. So there is my jquery-file-upload initializer, which uploads all photos in one request (creating item model) and then redirecting to the root of your app (you need to use item form):

<script type="text/javascript" charset="utf-8">
    var num_added = 0;
    var added = 0;
    var all_data = {};
    $(function () {
        // Initialize the jQuery File Upload widget:
        $('#fileupload').fileupload({
          complete: function (e, data) {
            window.location = "<%= root_url %>";
        },
          singleFileUploads: false
        })  .bind('fileuploadadd', function (e, data) {num_added++;})
            .bind('fileuploadsubmit', function (e, data) {
            if(added < num_added)
            {
            if (added == 0)
            all_data = data;
            else
            {
            $.each(data['files'], function(i, file){
            all_data['files'].push(file);
            });
            $.each(data['context'], function(i, context){
            all_data['context'].push(context);
            });
            }
            added++;
            if (added == num_added)
            {
            added++;
            all_data.submit();
            }
            return false;
            }
            })
            .bind('fileuploadsend', function (e, data) {num_added = 0; added = 0;});

        // 
        // Load existing files:
        $.getJSON($('#fileupload').prop('action'), function (files) {
          var fu = $('#fileupload').data('blueimpFileupload'), 
            template;
          fu._adjustMaxNumberOfFiles(-files.length);
          console.log(files);
          template = fu._renderDownload(files)
            .appendTo($('#fileupload .files'));
          // Force reflow:
          fu._reflow = fu._transition && template.length &&
            template[0].offsetWidth;
          template.addClass('in');
          $('#loading').remove();
        });

    });
  </script>

4 Comments

This looks like a great project! I'm adapting it to mine but can't seem to get around the auto upload (which is actually set to False by default). Did you have to do anything special to get that working? Mine isn't auto-uploading, although the cancel button is showing. Initial thoughts?
I didn't do anything special with autoupload. In my case I needed user to choose all his pictures and then press Upload button by himself.
And why you don't need cancel button? OK, you can easily hide it with CSS or find in html and delete it.
I see the form trying to submit with blob:localhost:5000/somestring. but the app isn't responding... I'll start a new thread!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.