2010-02-26 2 views
15

Paperclip - отличный загрузочный плагин для Rails. Сохранение загрузок в локальной файловой системе или Amazon S3, похоже, хорошо работает. Я бы просто предположил файлы хранилища на локальном хосте, но для этого приложения требуется использование S3, поскольку оно будет размещено на Heroku.Застежка-молния все вложения скрепки, хранящиеся на S3

Как я могу получить все мои загрузки/вложения с S3 в одной загруженной zip-загрузке?

Получение zip-файлов из локальной файловой системы кажется прямым. Он получает файлы из S3, которые меня озадачили. Я думаю, что это может быть связано с тем, как rubyzip обрабатывает файлы, на которые ссылается 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 
      } 
+0

интересно, если решение здесь использовать камень AWS-S3 в получить все файлы в ведро и не использовать paperclip? – chaserx

+0

Вы почти наверняка хотите использовать to_file() вместо url(). – vladr

+0

Да. Я тоже об этом тоже. Дает эту ошибку. не может конвертировать Paperclip :: Tempfile в String – chaserx

ответ

11

Вы почти наверняка хотите использовать e.abstract.to_file.path вместо e.abstract.url(...).

См:

UPDATE

От changelog:

Новое в версии 3.0.1:

  • API CHANGE: #to_file удален. Используйте вместо этого метод #copy_to_local_file.
+0

Спасибо, Влад. Кажется, он работает сейчас. – chaserx

+0

обновите этот ответ на paperclip> 3.0, .to_file был удален :( –

+0

@DavidMauricio Я обновил ответ. – vladr

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 
     } 
+0

Можете ли вы объяснить, почему ваше решение заставляет сборщик мусора ждать? Благодаря! – Jared

+1

Я не могу объяснить, почему это работает, но может подтвердить, что у меня была такая же проблема, и это исправлено! – Oll

+0

Что такое 'b +' в методе File.open? Я считаю, что есть только «r (+)», «w (+)» и «a (+)». – Marc

Смежные вопросы