Multiple files upload with Rails 3 and paperclip on heroku

寵の児 提交于 2019-11-28 19:58:47

You can look at jQuery-File-Upload. Demo here and rails 3/Paperclip setup here.

Edit: As @apneadiving mentioned, the library has been updated to version 5. The script you have is for verison 4. You should try modifying this to work with PaperClip. Copy-pasting the majority of the example code into my app (with a few modifications) worked for me:


#app/public/javascripts/application.js
$(function () {
  // Initialize the jQuery File Upload widget:
  $('#fileupload').fileupload();

  // Load existing files:
  $.getJSON($('#fileupload form').prop('action'), function (files) {
    var fu = $('#fileupload').data('fileupload');
    fu._adjustMaxNumberOfFiles(-files.length);
    fu._renderDownload(files)
        .appendTo($('#fileupload .files'))
        .fadeIn(function () {
          // Fix for IE7 and lower:
          $(this).show();
         });
    });

    // Open download dialogs via iframes,
    // to prevent aborting current uploads:
    $('#fileupload .files a:not([target^=_blank])').live('click', function (e) {
      e.preventDefault();
      $('<iframe style="display:none;"></iframe>')
        .prop('src', this.href)
        .appendTo('body');
    });

});

#app/controllers/uploads_controller.rb
def create
  @upload = Upload.new(params[:upload])
  if @upload.save
    render :json => [{ 
              :pic_path => @upload.attachment.url.to_s ,
              :name => @upload.attachment.instance.attributes["picture_file_name"]
            }], :content_type => 'text/html'
  else
    render [:json => { :result => 'error'}], :content_type => 'text/html'
  end
end

#app/views/uploads/new.html.haml
  %link#theme{:href => "http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/themes/base/jquery-ui.css", :rel => "stylesheet"}
    = stylesheet_link_tag 'jquery.fileupload-ui'
    #fileupload
      = form_for Upload.new, :html => { :multipart => true } do |f|
        .fileupload-buttonbar
          %label.fileinput-button
            %span Add files...
            = f.file_field :attachment, :multiple => true
          %button.start{:type => "submit"} Start upload
          %button.cancel{:type => "reset"} Cancel upload
          %button.delete{:type => "button"} Delete files
      .fileupload-content
        %table.files
        .fileupload-progressbar
    %script#template-upload{:type => "text/x-jquery-tmpl"}
      %tr{:class => "template-upload{{if error}} ui-state-error{{/if}}"}
        %td.preview
        %td.name ${name}
        %td.size ${sizef}
        {{if error}}
        %td.error{:colspan => "2"}
          Error:
          {{if error === 'custom_failure'}}Custom Error Message
          {{else}}${error}
          {{/if}}
        {{else}}
        %td.progress
          %div
        %td.start
          %button Start
        {{/if}}
        %td.cancel
          %button Cancel
    %script#template-download{:type => "text/x-jquery-tmpl"}
      %tr{:class => "template-download{{if error}} ui-state-error{{/if}}"}
        {{if error}}
        %td
        %td.name ${name}
        %td.size ${sizef}
        %td.error{:colspan => "2"}
          Error:
          {{if error === 1}}File exceeds upload_max_filesize (php.ini directive)
          {{else}}${error}
          {{/if}}
        {{else}}
        %td.preview
          {{if thumbnail_url}}
          %a{:href => "${url}", :target => "_blank"}
            %img{:src => "${thumbnail_url}"}/
          {{/if}}
        %td.name
          <a href="${url}"{{if thumbnail_url}} target="_blank"{{/if}}>${name}
        %td.size ${sizef}
        %td{:colspan => "2"}
        {{/if}}
        %td.delete
          %button{"data-type" => "${delete_type}", "data-url" => "${delete_url}"} Delete

Edit Had a quick look at your app, the problem is that you are mixing prototype with jquery. The easiest way around this is to switch to jQuery using jquery-rails.

#Gemfile
gem 'jquery-rails'

Next, run bundle install and then rails g jquery:install.

Then change your app/views/layouts/application.erb to this:

<%= stylesheet_link_tag :all %>
<%= csrf_meta_tag %>

<%= javascript_include_tag 'jquery.min' %>
<%= javascript_include_tag 'jquery-ui-1.8.13.custom.min' %>
<%= javascript_include_tag 'jquery.tmpl.min' %>
<%= javascript_include_tag 'jquery.iframe-transport' %>
<%= javascript_include_tag 'jquery.fileupload' %>
<%= javascript_include_tag 'jquery.fileupload-ui' %>
<%= javascript_include_tag 'jquery_ujs' %>
<%= javascript_include_tag 'application' %>

Note that I removed the

<%= javascript_include_tag :defaults %>

So that I can specify the order in which jquery, jquery_ujs, and application are loaded.

I've begun with a very similar task recently, and the swf plugin (at least the more recent one) will indeed let you update paperclip's record. It has callbacks for just about everything you'd need to extend.

:onUploadComplete (upload_options,event)

Here's Nathan Colgate's gist on the matter. He just makes a remote call to the rails server once the upload is finished telling it of the locations for the paperclip attachment.

from his uploadCompleteHandler

var uploadCompleteHandler = function(upload_options,event){
$.ajax({
      url: '<%= notify_rails_of_successful_upload_path(:format => :js)%>',
      global: false,
      type: 'POST',
      data: ({
        'authenticity_token' : '<%= form_authenticity_token %>',
    'upload' : {
        'file_file_name' : upload_options.FileName,
            'file_file_size' : upload_options.FileSize,
            'file_content_type' : upload_options.ContentType
    }
    }),
      dataType: 'script'
   }
)
};

I'm not sure if this exact callback gets triggered for each file; it definitely looks like it would. But he passes everything paperclip needs back through an ajax request. filename,size,content-type. This way all that gets sent to heroku is some text about the file, sparing your app a good amount of work by giving it to the client.

edit: flash is the only way I've found to avoid sending a lot of data through heroku to s3. There are a few html5/js-only uploaders that might be able to get the job done, but the ones I have found are still pretty ripe on the dev tree.

As per Heroku support, see this.

Paperclip & multiple files upload, although not S3 specific.

View: (notice the array blog_post[avatars][])

<form accept-charset="UTF-8" action="/blog_posts" enctype="multipart/form-data" id="new_blog_post" method="post">
<div style="margin:0;padding:0;display:inline">
<input name="utf8" type="hidden" value="&#x2713;" />
<input name="authenticity_token" type="hidden" value="<%=form_authenticity_token %>" />
</div>
<p><input id="blog_post" name="blog_post[avatars][]" type="file" multiple /></p>
<p><input name="commit" type="submit" value="Upload" /></p>
</form>

Controller:

# POST /blog_posts
# POST /blog_posts.json
def create

    @blog_post = BlogPost.new(params[:blog_post])

    @blog_post.avatars.each do |avatar|

        each_blog_post = BlogPost.new

        each_blog_post.avatar = avatar

        if each_blog_post.save

        end

    end

end

Model:

class BlogPost < ActiveRecord::Base

    attr_accessible :title, :avatar, :avatars

    has_attached_file :avatar

    attr_accessor :avatars

end
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!