2010-02-26 62 views
15

Kẹp giấy là một plugin tải lên tuyệt vời cho Rails. Lưu trữ video tải lên trên hệ thống tệp cục bộ hoặc Amazon S3 dường như hoạt động tốt. Tôi chỉ giả sử lưu trữ các tập tin trên localhost, nhưng việc sử dụng S3 là cần thiết cho ứng dụng này vì nó sẽ được lưu trữ trên Heroku.Nén tất cả các tệp đính kèm Kẹp giấy được lưu trữ trên S3

Tôi làm cách nào để tải tất cả các tệp tải lên/tệp đính kèm của tôi từ S3 trong một lần tải xuống được nén?

Lấy một tệp zip từ hệ thống tệp cục bộ có vẻ thẳng về phía trước. Nó nhận được các tập tin từ S3 khiến tôi bối rối. Tôi nghĩ rằng nó có thể có một cái gì đó để làm với cách rubyzip xử lý các tập tin được tham chiếu bởi URL. Tôi đã thử các cách tiếp cận khác nhau nhưng dường như không tránh được lỗi.

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

Tự hỏi nếu giải pháp ở đây là sử dụng đá quý AWS-S3 để nhận tất cả các tệp trong thùng và không sử dụng kẹp giấy? – chaserx

+0

Bạn gần như chắc chắn muốn sử dụng to_file() thay vì url(). – vladr

+0

Vâng. Tôi cũng vậy. Cung cấp lỗi này. không thể chuyển đổi Paperclip :: Tempfile thành String – chaserx

Trả lời

11

Bạn gần như chắc chắn muốn sử dụng e.abstract.to_file.path thay vì e.abstract.url(...).

Xem:

CẬP NHẬT

Từ changelog:

Mới trong 3.0.1:

  • API THAY ĐỔI: #to_file đã bị xóa. Sử dụng phương pháp #copy_to_local_file để thay thế.
+0

Cảm ơn, Vlad. Nó có vẻ hoạt động ngay bây giờ. – chaserx

+0

cập nhật câu trả lời này cho kẹp giấy> 3.0, .to_file đã bị xóa: ( –

+0

@DavidMauricio Tôi đã cập nhật câu trả lời – vladr

2

@ giải pháp của vlard là ok. Tuy nhiên, tôi đã gặp phải một số vấn đề với to_file. Nó tạo ra một tempfile và bộ thu gom rác sẽ xóa (đôi khi) tệp trước khi nó được thêm vào tệp nén. Do đó, tôi nhận được các lỗi Errno::ENOENT: No such file or directory ngẫu nhiên.

Vì vậy, tôi đang sử dụng đoạn mã sau bây giờ (tôi đã giữ ban đầu tên biến mã cho phù hợp với câu hỏi ban đầu)

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

Bạn có thể giải thích tại sao giải pháp của bạn buộc bộ thu gom rác phải đợi? Cảm ơn! – Jared

+1

Tôi không thể giải thích lý do tại sao nó hoạt động, nhưng có thể xác nhận rằng tôi đã có cùng một vấn đề chính xác và điều này đã sửa nó! – Oll

+0

'b +' trong phương thức File.open là gì? Tôi tin rằng chỉ có 'r (+)', 'w (+)' và 'a (+)'. – Marc

Các vấn đề liên quan