4

I am implementing feature which allows user to either download single file or multiple files from S3. Single file downloading is working properly, but for multiple files I am receiving error on Heroku,

Errno::ENOENT (No such file or directory @ rb_file_s_lstat )

Controller code snippet for downloading files as zip format is as below,

def method_name
   zipfile_name = "#{Rails.root}/public/archive.zip"
   Zip::File.open(zipfile_name, Zip::File::CREATE) do |zipfile |
     @transfer.transfer_attachments.each do |attachment | 
       zipfile.add(attachment.avatar.file.filename, attachment.avatar.url)
     end
   end
   send_file(File.join("#{Rails.root}/public/", 'archive.zip'), : type =>
'application/zip', : filename => "#{Time.now.to_date}.zip")
end

Gemfile

ruby '2.3.1'

gem 'rails', '~> 5.0.1'

gem 'rubyzip', '>= 1.0.0'

gem 'zip-zip'

This zipfile functionality works proper with locally stored files.

Mansi Shah
  • 517
  • 5
  • 15

2 Answers2

6

I would like to answer to my question. Steps are as follow,

  1. Downlaod files from S3 and store them locally
  2. Add them to zip by first creating zip and then add files to it.
  3. Download zip archive

Here is controller code,

require 'open-uri'

def download_all_files
   folder_path = "#{Rails.root}/public/downloads/"
   zipfile_name = "#{Rails.root}/public/archive.zip"

   FileUtils.remove_dir(folder_path) if Dir.exist?(folder_path)
   FileUtils.remove_entry(zipfile_name) if File.exist?(zipfile_name)
   Dir.mkdir("#{Rails.root}/public/downloads")

   @model_object.each do |attachment|
      open(folder_path + "#{attachment.avatar.file.filename}", 'wb') do |file|
         file << open("#{attachment.avatar.url}").read
      end
   end

   input_filenames = Dir.entries(folder_path).select {|f| !File.directory? f}

   Zip::File.open(zipfile_name, Zip::File::CREATE) do |zipfile|
      input_filenames.each do |attachment|
         zipfile.add(attachment,File.join(folder_path,attachment))
      end
   end

   send_file(File.join("#{Rails.root}/public/", 'archive.zip'), :type => 'application/zip', :filename => "#{Time.now.to_date}.zip")

end
Mansi Shah
  • 517
  • 5
  • 15
2

Guess: You are adding attachments as urls, but you should be adding (local) file paths instead.

zwippie
  • 15,050
  • 3
  • 39
  • 54
  • All the files are uploaded to S3. And in `zipfile.add()` I am passing filename and its actual URL (Stored on S3). One other important thing is, this code works properly with locally stored files. – Mansi Shah Jun 22 '17 at 09:41
  • 1
    That's what I meant to say: you probably have to download the files from S3 first before the zip library can add them to your zipfile. – zwippie Jun 22 '17 at 15:58
  • Yes got it. I will implement it. Thanks – Mansi Shah Jun 22 '17 at 17:48