Skip to content

Instantly share code, notes, and snippets.

@janko
Created October 29, 2018 22:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save janko/f6819c72e5b24041237320f39766c1e8 to your computer and use it in GitHub Desktop.
Save janko/f6819c72e5b24041237320f39766c1e8 to your computer and use it in GitHub Desktop.
Zip unpacking with Shrine while retaining the same directory structure
require "sequel"
require "shrine"
require "shrine/storage/memory"
require "zip"
require "tempfile"
require "securerandom"
DB = Sequel.sqlite
DB.create_table :archives do
primary_key :id
String :attachment_data
end
Shrine.storages = {
cache: Shrine::Storage::Memory.new,
store: Shrine::Storage::Memory.new,
}
Shrine.plugin :sequel
Shrine.plugin :versions
class FileUploader < Shrine
def generate_location(io, metadata: {}, record: nil, **)
if metadata["from_zip"]
# retain location when uploading to permanent storage
File.join("archive/#{record.id}", metadata.fetch("filename"))
else
super
end
end
end
class Archive < Sequel::Model
include FileUploader::Attachment.new(:attachment)
end
zip = Tempfile.new(binmode: true)
Zip::File.open(zip.path, Zip::File::CREATE) do |zip_file|
zip_file.get_output_stream("foo.txt") { |f| f.write "foo" }
zip_file.get_output_stream("bar/baz.txt") { |f| f.write "barbaz" }
end
zip.flush
destination_directory = "archive/#{SecureRandom.hex}"
versions = { files: [] }
Zip::File.foreach(zip.path) do |entry|
upload_location = File.join(destination_directory, entry.name)
cache = FileUploader.new(:cache)
entry.get_input_stream do |stream|
cached_file = cache.upload stream,
location: upload_location,
metadata: {
"filename" => entry.name,
"size" => entry.size,
}
cached_file.metadata["from_zip"] = true
versions[:files] << cached_file
end
end
archive = Archive.new
archive.attachment_attacher.set(versions)
archive.save
archive.attachment[:files]
# => [#<FileUploader::UploadedFile:0x00007febfca079c8
# @data=
# {"id"=>"archive/1/foo.txt",
# "storage"=>"store",
# "metadata"=>
# {"filename"=>"foo.txt",
# "size"=>3,
# "mime_type"=>nil,
# "from_zip"=>true}}>,
# #<FileUploader::UploadedFile:0x00007febfca07838
# @data=
# {"id"=>"archive/1/bar/baz.txt",
# "storage"=>"store",
# "metadata"=>
# {"filename"=>"bar/baz.txt",
# "size"=>6,
# "mime_type"=>nil,
# "from_zip"=>true}}>]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment