Skip to content

Instantly share code, notes, and snippets.

@aileron
Created June 16, 2020 02:12
Show Gist options
  • Save aileron/6d3467ffcbeec9bf1d319cac5ae810e1 to your computer and use it in GitHub Desktop.
Save aileron/6d3467ffcbeec9bf1d319cac5ae810e1 to your computer and use it in GitHub Desktop.
ActiveStorageDownloader
# frozen_string_literal: true
module ActiveStorageDownloader
refine ActiveStorage::Blob do
def download_to(tempdir: nil, &block)
DownloadTo.new(self, tempdir: tempdir).download_blob_to_tempfile(&block)
end
end
using self
def self.download(name = :disk)
STDOUT.puts "#{ActiveStorage::Blob.count} Blobs to go..."
STDOUT.puts "max: #{ActiveStorage::Blob.maximum(:id)}"
configs = Rails.configuration.active_storage.service_configurations
to_service = ActiveStorage::Service.configure(name, configs)
ActiveStorage::Blob.find_each do |blob|
blob.download_to do |tf|
to_service.upload(blob.key, tf, checksum: blob.checksum)
end
STDOUT.print "##{blob.id}\n"
end
end
class DownloadTo
def initialize(blob, tempdir: nil)
@blob = blob
@tempdir = tempdir
end
def download_blob_to_tempfile
open_tempfile do |file|
download_blob_to file
verify_integrity_of file
yield file
end
rescue Aws::S3::Errors::NotFound
blob.delete
end
private
attr_reader :blob, :tempdir
def open_tempfile
file = Tempfile.open(["ActiveStorage-#{blob.id}-", blob.filename.extension_with_delimiter], tempdir)
begin
yield file
ensure
file.close!
end
end
def download_blob_to(file)
file.binmode
blob.download { |chunk| file.write(chunk) }
file.flush
file.rewind
end
def verify_integrity_of(file)
fail ActiveStorage::IntegrityError unless Digest::MD5.file(file).base64digest == blob.checksum
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment