Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to download multiple files from S3 as Zip format in Rails 5.x.x app?

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.

like image 967
Mansi Shah Avatar asked Feb 04 '23 05:02

Mansi Shah


1 Answers

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
like image 151
Mansi Shah Avatar answered Feb 06 '23 19:02

Mansi Shah