简体   繁体   English

Rails - Paper_Clip - 支持多文件上传

[英]Rails - Paper_Clip - Support for Multi File Uploads

I have paper_clip installed on my Rails 3 app, and can upload a file - wow that was fun and easy! 我在我的Rails 3应用程序上安装了paper_clip,并且可以上传文件 - 哇这很有趣而且简单!

Challenge now is, allowing a user to upload multiple objects. 现在的挑战是,允许用户上传多个对象。 Whether it be clicking select fileS and being able to select more than one. 是否单击选择文件并能够选择多个文件。 Or clicking a more button and getting another file upload button. 或者单击更多按钮并获取另一个文件上载按钮。

I can't find any tutorials or gems to support this out of the box. 我无法找到任何教程或宝石来支持这种开箱即用。 Shocking I know... 令人震惊我知道......

Any suggestions or solutions. 任何建议或解决方案。 Seems like a common need? 似乎是一个共同的需求?

Thanks 谢谢

Okay, this is a complex one but it is doable. 好的,这是一个复杂的,但它是可行的。 Here's how I got it to work. 以下是我如何使用它。

On the client side I used http://github.com/valums/file-uploader , a javascript library which allows multiple file uploads with progress-bar and drag-and-drop support. 在客户端,我使用了http://github.com/valums/file-uploader ,这是一个javascript库,允许多个文件上传,带有进度条和拖放支持。 It's well supported, highly configurable and the basic implementation is simple: 它受到良好支持,高度可配置,基本实现很简单:

In the view: 在视图中:

<div id='file-uploader'><noscript><p>Please Enable JavaScript to use the file uploader</p></noscript></div>

In the js: 在js中:

var uploader = new qq.FileUploader({
   element: $('#file-uploader')[0],
   action: 'files/upload',
   onComplete: function(id, fileName, responseJSON){
     // callback
   }
});

When handed files, FileUploader posts them to the server as an XHR request where the POST body is the raw file data while the headers and filename are passed in the URL string (this is the only way to upload a file asyncronously via javascript). 当传递文件时,FileUploader将它们作为XHR请求发布到服务器,其中POST主体是原始文件数据,而头文件和文件名在URL字符串中传递(这是通过javascript异步上传文件的唯一方法)。

This is where it gets complicated, since Paperclip has no idea what to do with these raw requests, you have to catch and convert them back to standard files (preferably before they hit your Rails app), so that Paperclip can work it's magic. 这是它变得复杂的地方,因为Paperclip不知道如何处理这些原始请求,你必须捕获它们并将它们转换回标准文件(最好是在它们点击你的Rails应用程序之前),这样Paperclip就能发挥它的魔力。 This is done with some Rack Middleware which creates a new Tempfile (remember: Heroku is read only): 这是通过一些Rack Middleware完成的,它创建了一个新的Tempfile(记住:Heroku是只读的):

# Embarrassing note: This code was adapted from an example I found somewhere online
# if you recoginize any of it please let me know so I pass credit.
module Rack
  class RawFileStubber

    def initialize(app, path=/files\/upload/) # change for your route, careful.
      @app, @path = app, path
    end

    def call(env)
      if env["PATH_INFO"] =~ @path
        convert_and_pass_on(env)
      end
      @app.call(env)
    end

    def convert_and_pass_on(env)
      tempfile = env['rack.input'].to_tempfile      
      fake_file = {
        :filename => env['HTTP_X_FILE_NAME'],
        :type => content_type(env['HTTP_X_FILE_NAME']),
        :tempfile => tempfile
      }
      env['rack.request.form_input'] = env['rack.input']
      env['rack.request.form_hash'] ||= {}
      env['rack.request.query_hash'] ||= {}
      env['rack.request.form_hash']['file'] = fake_file
      env['rack.request.query_hash']['file'] = fake_file
      if query_params = env['HTTP_X_QUERY_PARAMS']
        require 'json'
        params = JSON.parse(query_params)
        env['rack.request.form_hash'].merge!(params)
        env['rack.request.query_hash'].merge!(params)
      end
    end

    def content_type(filename)
      case type = (filename.to_s.match(/\.(\w+)$/)[1] rescue "octet-stream").downcase
      when %r"jp(e|g|eg)"            then "image/jpeg"
      when %r"tiff?"                 then "image/tiff"
      when %r"png", "gif", "bmp"     then "image/#{type}"
      when "txt"                     then "text/plain"
      when %r"html?"                 then "text/html"
      when "js"                      then "application/js"
      when "csv", "xml", "css"       then "text/#{type}"
      else 'application/octet-stream'
      end
    end
  end
end

Later, in application.rb: 稍后,在application.rb中:

config.middleware.use 'Rack::RawFileStubber'

Then in the controller: 然后在控制器中:

  def upload
    @foo = modelWithPaperclip.create({ :img => params[:file] })
  end

This works reliably, though it can be a slow process when uploading a lot of files simultaneously. 这种方法可靠,但在同时上传大量文件时可能会很慢。

DISCLAIMER 免责声明

This was implemented for a project with a single, known & trusted back-end user. 这是针对具有单个,已知且受信任的后端用户的项目实现的。 It almost certainly has some serious performance implications for a high traffic Heroku app and I have not fire tested it for security. 它几乎肯定会对高流量Heroku应用程序产生一些严重的性能影响,并且我没有为安全性进行过防火测试。 That said, it definitely works. 那说,它绝对有效。

The method Ryan Bigg recommends is here: Ryan Bigg建议的方法是:

The file-uploader recommendation by Daniel Mendel is really great. Daniel Mendel的file-uploader推荐非常棒。 It's a seriously awesome user experience, like Gmail drag-and-drop uploads. 这是一个非常棒的用户体验,比如Gmail拖放上传。 Someone wrote a blog post about how to wire it up with a rails app using the rack-raw-upload middleware, if you're interested in an up-to-date middleware component. 如果你对最新的中间件组件感兴趣,有人写了一篇关于如何使用rack-raw-upload中间件连接rails应用程序的博客文章。

There's also another plugin that's been updated more recently which may be useful 还有一个最近更新的插件可能很有用

And another one (Included for completeness. I haven't investigated this one.) 另一个(包括完整性。我没有调查过这个。)

These questions are highly related 这些问题高度相关

I cover this in Rails 3 in Action 's Chapter 8. I don't cover uploading to S3 or resizing images however. 在Action的第8章中的Rails 3中介绍了这一点。但我没有介绍上传到S3或调整图像大小。

Recommending you buy it based solely on it fixing this one problem may sound a little biased, but I can just about guarantee you that it'll answer other questions you have down the line. 建议你单独购买它来解决这个问题可能听起来有点偏颇,但我可以保证你会回答你的其他问题。 It has a Behaviour Driven Development approach as one of the main themes, introducing you to Rails features during the development of an application. 它将行为驱动开发方法作为主要主题之一,在开发应用程序期间向您介绍Rails功能。 This shows you not only how you can build an application, but also make it maintainable . 这不仅向您展示了如何构建应用程序,还使其可维护

As for the resizing of images after they've been uploaded, Paperclip's got pretty good documentation on that . 至于上传后的图像大小调整,Paperclip有相当好的文档 I'd recommend having a read and then asking another question on SO if you don't understand any of the options / methods. 如果您不理解任何选项/方法,我建议您阅读,然后在SO上提出另一个问题。

And as for S3 uploading, you can do this: 至于S3上传,你可以这样做:

has_attached_file :photo, :styles => { ... }, :storage => :s3

You'd need to configure Paperclip::Storage::S3 with your S3 details to set it up, and again Paperclip's got some pretty awesome documentation for this. 您需要使用S3详细信息配置Paperclip::Storage::S3以进行设置,Paperclip再次为此提供了一些非常棒的文档

Good luck! 祝好运!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM