Rails - Paper_Clip - 支持多文件上传

Posted

技术标签:

【中文标题】Rails - Paper_Clip - 支持多文件上传【英文标题】:Rails - Paper_Clip - Support for Multi File Uploads 【发布时间】:2011-04-29 10:03:45 【问题描述】:

我在我的 Rails 3 应用程序上安装了 paper_clip,并且可以上传文件 - 哇,太有趣了!

现在的挑战是,允许用户上传多个对象。 是否单击选择文件并能够选择多个。或者单击更多按钮并获取另一个文件上传按钮。

我找不到任何开箱即用的教程或 gem 来支持这一点。震惊我知道...

任何建议或解决方案。似乎是一个共同的需求?

谢谢

【问题讨论】:

忘记添加了。我正在上传需要调整大小的图像。这就是为什么我不能直接上传到 S3。我正在使用heroku进行托管。谢谢 【参考方案1】:

好的,这是一个复杂的,但它是可行的。这是我如何让它工作的。

在客户端,我使用了 http://github.com/valums/file-uploader,这是一个 javascript 库,它允许通过进度条和拖放支持上传多个文件。它得到很好的支持、高度可配置且基本实现很简单:

在视图中:

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

在js中:

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

当提交文件时,FileUploader 将它们作为 XHR 请求发布到服务器,其中 POST 正文是原始文件数据,而标题和文件名在 URL 字符串中传递(这是通过 javascript 异步上传文件的唯一方法)。

这是复杂的地方,因为 Paperclip 不知道如何处理这些原始请求,您必须捕获并将它们转换回标准文件(最好在它们到达您的 Rails 应用程序之前),以便 Paperclip 可以工作魔法。这是通过一些创建新临时文件的机架中间件完成的(记住: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

稍后,在 application.rb 中:

config.middleware.use 'Rack::RawFileStubber'

然后在控制器中:

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

这很可靠,但同时上传大量文件时可能会很慢。

免责声明

这是针对具有单个、已知且受信任的后端用户的项目实施的。几乎可以肯定,它对高流量 Heroku 应用程序有一些严重的性能影响,我还没有对它进行安全测试。也就是说,它确实有效。

【讨论】:

哇,谢谢...但是如果它“创建一个新的 Tempfile”,它与 Heroku 不兼容吗?除非我错过了什么? OK 结果证明 heroku 确实有一个临时图像的位置。其他问题。类 RawFileStubber 去哪里了? 我将 raw_file_stubber.rb 文件添加到 /lib ...然后添加了上面的 application.rb 配置设置并尝试启动服务器(rails s)但遇到了各种错误。 Q,上面的 Rails 3 友好吗? @丹尼尔。我想我搞定了。我在硬盘上看到临时文件,但它们都是 TXT 文件。服务器出错“无法将 nil 转换为字符串”app/controllers/photos_controller.rb:4:in upload' lib/raw_file_stubber.rb:13:in call' @丹尼尔。这样做的问题还在于它现在只能与一种模型一起使用。有没有一种通用的方法来支持这一点,以便它适用于几种不同类型的模型上传?【参考方案2】:

Ryan Bigg 推荐的方法在这里:

https://github.com/rails3book/ticketee/commit/cd8b466e2ee86733e9b26c6c9015d4b811d88169 https://github.com/rails3book/ticketee/commit/982ddf6241a78a9e6547e16af29086627d9e72d2

Daniel Mendel 的 file-uploader 推荐真的很棒。这是一种非常棒的用户体验,就像 Gmail 拖放上传一样。如果您对最新的中间件组件感兴趣,有人写了一篇关于如何使用rack-raw-upload 中间件将其与 Rails 应用程序连接起来的博客文章。

http://pogodan.com/blog/2011/03/28/rails-html5-drag-drop-multi-file-upload https://github.com/newbamboo/rack-raw-upload http://marc-bowes.com/2011/08/17/drag-n-drop-upload.html

还有另一个最近更新的插件可能有用

jQuery-File-Upload Rails setup instructions Rails setup instructions for multiples

还有一个(包括在内是为了完整性。我没有调查过这个。)

PlUpload plupload-rails3

这些问题高度相关

Drag-and-drop file upload in Google Chrome/Chromium and Safari? jQuery Upload Progress and AJAX file upload

【讨论】:

【参考方案3】:

我在 Rails 3 in Action 的第 8 章中介绍了这一点。但是,我不介绍上传到 S3 或调整图像大小。

仅根据它解决这个问题来推荐您购买它可能听起来有点偏颇,但我可以向您保证,它会回答您的其他问题。它以行为驱动开发方法作为主要主题之一,在应用程序开发过程中向您介绍 Rails 功能。这不仅向您展示了如何构建应用程序,而且还向您展示了如何可维护

关于图片上传后的大小调整,Paperclip 有pretty good documentation on that。如果您不了解任何选项/方法,我建议您阅读然后再问另一个关于 SO 的问题。

对于 S3 上传,您可以这样做:

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

您需要使用您的 S3 详细信息配置 Paperclip::Storage::S3 来进行设置,Paperclip 再次为此提供了一些 pretty awesome documentation。

祝你好运!

【讨论】:

以上是关于Rails - Paper_Clip - 支持多文件上传的主要内容,如果未能解决你的问题,请参考以下文章

mfc多文档子窗口最大化后怎样去掉右上角的系统按钮(最大化,最小化和关闭)

Rails 二进制流支持

Rack / Rails 中的 HTTP/2 支持

Ruby on Rails 应用程序的 OpenID 支持

为啥 Rails4 放弃了对 Gemfile 中“资产”组的支持

ruby Ruby / Rails支持的版本矩阵