Bitwise
Bitwise

Reputation: 8461

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.

Upvotes: 3

Views: 914

Answers (1)

MrShemek
MrShemek

Reputation: 2483

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.

Upvotes: 2

Related Questions