How to unzip a file in Ruby on Rails?

Ruby on-RailsRubyFileZip

Ruby on-Rails Problem Overview


I'm uploading a file to the server in Ruby on Rails

Normally, it's a text file and I save it in the model as a 'file' field in a Submission ActiveRecord with other fields such as title of submission.. etc.

However, the user can also submit a zip file. In this case the zipfile should unzipped and for each file in the zip a new Submission should be created with the same text fields, but current file.

How can I accomplish this?

I looked at unzip examples on the net, but most use a directory to unzip the files to. I'm not sure if I need that as in the current create method of SubmissionsController, a file object is received and I presume the path to save the file to is automatically generated when the Submission save method is called. So I was thinking that maybe I should unzip the zipfile in memory to get an array of file objects and then create a new Submission with each file object but same fields and then let ActiveRecord generate the file paths for each one when it saves them to the database. I might be wrong here, because I'm kind of new to Rails and Ruby.

Ruby on-Rails Solutions


Solution 1 - Ruby on-Rails

I'd use the rubyzip gem. Specifically this part: https://github.com/rubyzip/rubyzip/blob/master/lib/zip/filesystem.rb

It creates an artificial file system in memory mirroring the contents of the zip file. Here's an example based of the example from the docs:

Rubyzip interface changed!!! No need to do require "zip/zip" and Zip prefix in class names removed.

require 'zip'

Zip::File.open("my.zip") do |zipfile|
  zipfile.each do |file|
    # do something with file
  end
end

In your case, just put the name of the uploaded tempfile where my.zip is in the example, and you can loop through the contents and do your regular operations on them.

Solution 2 - Ruby on-Rails

From the RubyZip project page:

> Rubyzip interface changed!!! No need to do require "zip/zip" and Zip prefix in class names removed.

So, the example code from @ben-lee should be updated to something like this:

require 'zip'

Zip::File.open("my.zip") do |zipfile|
  zipfile.each do |file|
    # do something with file
  end
end

Solution 3 - Ruby on-Rails

Extract Zip files in Ruby

Once you've installed the rubyzip gem, you can use this method to extract zip files:

require 'zip'

def extract_zip(file, destination)
  FileUtils.mkdir_p(destination)

  Zip::File.open(file) do |zip_file|
    zip_file.each do |f|
      fpath = File.join(destination, f.name)
      zip_file.extract(f, fpath) unless File.exist?(fpath)
    end
  end
end

You use it like this:

extract_zip(zip_path, extract_destination)

Solution 4 - Ruby on-Rails

Worked for me:

gem install rubyzip

main.rb

require 'zip'

def extract_zip(file, destination)
  FileUtils.mkdir_p(destination)

  Zip::File.open(file) do |zip_file|
    zip_file.each do |f|
      fpath = File.join(destination, f.name)
      FileUtils.mkdir_p(File.dirname(fpath))
      zip_file.extract(f, fpath) unless File.exist?(fpath)
    end
  end
end

extract_zip('file.zip', 'tmp')

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionsiamiiView Question on Stackoverflow
Solution 1 - Ruby on-RailsBen LeeView Answer on Stackoverflow
Solution 2 - Ruby on-RailsBill IngramView Answer on Stackoverflow
Solution 3 - Ruby on-RailsSheharyarView Answer on Stackoverflow
Solution 4 - Ruby on-RailsinstalleroView Answer on Stackoverflow