15

Paperclip 是一个很棒的 Rails 上传插件。将上传内容存储在本地文件系统或 Amazon S3 上似乎效果很好。我只是假设将文件存储在本地主机上,但是这个应用程序需要使用 S3,因为它将托管在 Heroku 上。

我将如何在一次压缩下载中从 S3 获取所有上传/附件?

本地文件系统获取文件的 zip 文件似乎很简单。它从 S3 获取文件让我感到困惑。我认为这可能与 ruby​​zip 处理 URL 引用的文件的方式有关。我尝试了各种方法,但似乎无法避免错误。

    format.zip {
                registrations_with_attachments = Registration.find_by_sql('SELECT * FROM registrations WHERE abstract_file_name NOT LIKE ""')
                headers['Cache-Control'] = 'no-cache'  
                tmp_filename = "#{RAILS_ROOT}/tmp/tmp_zip_" <<
                                Time.now.to_f.to_s <<
                                ".zip"

                # rubyzip gem version 0.9.1
                # rdoc http://rubyzip.sourceforge.net/                
                Zip::ZipFile.open(tmp_filename, Zip::ZipFile::CREATE) do |zip|
                  #get all of the attachments

                  # attempt to get files stored on S3
                  # FAIL
                  registrations_with_attachments.each { |e| zip.add("abstracts/#{e.abstract.original_filename}", e.abstract.url(:original, false)) }
                  # => No such file or directory - http://s3.amazonaws.com/bucket/original/abstract.txt
                  # Should note that these files in S3 bucket are publicly accessible. No ACL. 

                  # works with local storage. Thanks to Henrik Nyh
                  # registrations_with_attachments.each { |e| zip.add("abstracts/#{e.abstract.original_filename}", e.abstract.path(:original))   }
                end     

                send_data(File.open(tmp_filename, "rb+").read, :type => 'application/zip', :disposition => 'attachment', :filename => tmp_filename.to_s)
                File.delete tmp_filename
          }
4

2 回答 2

11

您几乎可以肯定要使用e.abstract.to_file.path而不是e.abstract.url(...).

看:

更新

变更日志

3.0.1 中的新功能:

于 2010-03-06T04:39:00.033 回答
2

@vlard 的解决方案还可以。但是我遇到了一些问题to_file。它会创建一个临时文件,垃圾收集器会在将文件添加到 zip 文件之前删除(有时)该文件。因此,我收到随机Errno::ENOENT: No such file or directory 错误。

所以我现在使用以下代码(我保留了初始代码变量名称以与初始问题保持一致)

format.zip {
            registrations_with_attachments = Registration.find_by_sql('SELECT * FROM registrations WHERE abstract_file_name NOT LIKE ""')
            headers['Cache-Control'] = 'no-cache'  

            #please note that using nanoseconds option in strftime reduces the risks concerning the situation where 2 or more  users initiate the download in the same time
            tmp_filename = "#{RAILS_ROOT}/tmp/tmp_zip_" <<
                            Time.now.strftime('%Y-%m-%d-%H%M%S-%N').to_s <<   
                            ".zip"

            # rubyzip gem version 0.9.4                
            zip = Zip::ZipFile.open(tmp_filename, Zip::ZipFile::CREATE) 
            zip.close

            registrations_with_attachments.each { |e|
                 file_to_add = e.file.to_file
                 zip = Zip::ZipFile.open(tmp_filename)
                 zip.add("abstracts/#{e.abstract.original_filename}", file_to_add.path)
                 zip.close
                 puts "added #{file_to_add.path} to #{tmp_filename}"  #force garbage collector to keep the file_to_add until after the file has been added to zip
            }

            send_data(File.open(tmp_filename, "rb+").read, :type => 'application/zip', :disposition => 'attachment', :filename => tmp_filename.to_s)
            File.delete tmp_filename
      }
于 2011-12-20T12:13:54.130 回答