Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Download multiple files with Carrierwave

I've enabled multiple uploading with Carrierwave. But now I'm trying to figure out how to download all of the uploads in one bulk action.

To be clear. I have an Attachment table that can have files. When I upload multiple files Carrierwave saves them just fine.

CURRENT ATTEMPT (NOT WORKING)

<div>
  <%= "#{index + 1}. Upload:" %>
  <%= link_to "Download", attachment.files[0].identifier, download: attachment.files[0].identifier %>
  <%= attachment.files[0].identifier %>
</div>

ERROR WHEN TRYING TO DOWNLOAD ONE FILE FROM THE FILES ARRAY:

ActionController::UnknownFormat (ComplianceSubmissionsController#edit is missing a template for this request format and variant.

request.formats: ["text/html"]
request.variant: []):

This error is not the real problem I suspect.

What I'm looking for is a way to bulk download files saved on S3 and uploaded with Carrierwave, it's been difficult to find good documentation on this as Carrierwave does not have any on this case.

like image 970
Bitwise Avatar asked Dec 10 '25 15:12

Bitwise


1 Answers

In our application, we are allowing clients to download multiple files as a ZIP file.

Example from my application

1) collect objects you want to ZIP

@objects_to_zip = Files.all

2) convert each object to a hash (not necessary but makes our life easier):

@objects_to_zip = @objects_to_zip.map(&:convert_object_to_a_hash)


#/app/models/file.rb
def convert_object_to_a_hash
  {
    name: sanitized_filename(FILE_NAME),
    extension: 'FILE_EXTENSION',
    content: FILE_CONTENT
  }
end

def sanitized_filename(file_name)
  max_name_length = 50

  Zaru.sanitize!(file_name, :padding=>(255-max_name_length)).gsub(/[[:punct:]]+/, ' ').gsub(/\p{S}/, ' ').gsub(/[[:space:]]+/, '_').downcase
end

3) create an archive and send the result to the client

send_data(create_archive(@objects_to_zip), :type => 'application/zip', :filename => "#{ZIP_FILENAME}.zip")

#app/helpers/zip_helpers.rb
module ZipHelpers

  def create_archive(files)
    string_io = Zip::OutputStream.write_buffer do |zio|
      Array(files).each do |file|
        zio.put_next_entry("#{file.fetch(:name).gsub('/', '-')}.#{file.fetch(:extension)}")
        zio.write file.fetch(:content)
      end
    end
    string_io.rewind
    string_io.read
  end

end

We are using two gems (but I am not sure if both of them are required here):
- rubyzip
- zip-zip

Warning

As far as I remember there is one problem with file names. If your file contains, for instance, Chinese characters, it will not unzip correctly on Windows machines. We solved it by removing those characters, and we added some strings (like file ID) to avoid empty filenames.

Hope that will help you.

like image 90
MrShemek Avatar answered Dec 13 '25 05:12

MrShemek



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!