DEV Community

Cover image for Unzip an archive and attach images to Active Record model objects
Masroor Hussain
Masroor Hussain

Posted on • Updated on

Unzip an archive and attach images to Active Record model objects

Recently I worked on a project where I had to upload a zip archive of images and then attach those images to Active Record model objects on the Rails server.

  • Note: This example uses Active Storage to attach images to Active Record objects.

Here is how I got it all working

Install Gem

Include this gem

gem 'rubyzip'
Enter fullscreen mode Exit fullscreen mode

then do

bundle install
Enter fullscreen mode Exit fullscreen mode

Unzipping and file attachment

We suppose an Active Record model named Product, which has an Active Storage attribute called product_image

class OrderItem < ApplicationRecord
  has_one_attached :product_image
end
Enter fullscreen mode Exit fullscreen mode

The controller which renders a zip upload form in the action zip_upload_form (view template code is not provided here) and the form gets posted to the zip_file action, which then processes the zip file by calling the process_zip_file method. It's better to put such code in a service but for the sake of this tutorial let's just put in the controller.

require 'zip'

class UnzipController < ApplicationController

  # GET
  def zip_upload_form
    # this action renders form for zip file upload
  end

  # POST
  def zip_file
    # the form is posted to this action
    # this action processes the uploaded zip file

    # params[:zip] is the uploaded zip file    
    if params[:zip]
      process_zip_file(params[:zip])
    else
      redirect_to zip_upload_form_path
    end
  end

  private

  def process_zip_file(tmpfile_zip)
    Zip::File.open(tmpfile_zip.path) do |zipfile|

      # iterating through all the entries found in the zip file
      zipfile.each do |entry|
        if entry.file?
          puts "#{entry.name} is a file!"
          attach_file_to_model_obj(entry)

        elsif entry.directory?
          puts "#{entry.name} is a directory!"

        elsif entry.symlink?
          puts "#{entry.name} is a symlink!"
        end

      end
    end
  end

  def attach_file_to_model_obj(entry)
    # first we create a temp file from the file found in the zip archive
    # then attach the temp file to model obj

    Tempfile.open(["my-filename", ".#{put_extension_here}"]) do |tmp|
      # this line creates the temp file
      entry.extract(tmp.path) { true }

      # attaching the temp image file to active record object
      Product.first
             .product_image
             .attach(io: File.open(tmp.path), filename: "my-filename.#{put_extension_here}")
    end
  end

end
Enter fullscreen mode Exit fullscreen mode

Cover Image by JOHN TOWNER on Unsplash

Top comments (0)