Add ActiveStorage::Blob#open

[David Robertson & George Claghorn]
This commit is contained in:
George Claghorn 2018-05-16 22:12:31 -04:00
parent bfe4248c78
commit ee21b7c2eb
8 changed files with 81 additions and 12 deletions

@ -1,3 +1,8 @@
* Add `ActiveStorage::Blob#open`, which downloads a blob to a tempfile on disk
and yields the tempfile. Deprecate `ActiveStorage::Downloading`.
*David Robertson, George Claghorn*
* Pass in `identify: false` as an argument when providing a `content_type` for
`ActiveStorage::Attached::{One,Many}#attach` to bypass automatic content
type inference. For example:

@ -1,5 +1,7 @@
# frozen_string_literal: true
require "active_storage/downloader"
# A blob is a record that contains the metadata about a file and a key for where that file resides on the service.
# Blobs can be created in two ways:
#
@ -164,6 +166,11 @@ def download(&block)
service.download key, &block
end
# Downloads the blob to a tempfile on disk. Yields the tempfile.
def open(&block)
ActiveStorage::Downloader.new(self).download_blob_to_tempfile(&block)
end
# Deletes the file on the service that's associated with this blob. This should only be done if the blob is going to be
# deleted as well or you will essentially have a dead reference. It's recommended to use the +#purge+ and +#purge_later+

@ -1,7 +1,5 @@
# frozen_string_literal: true
require "active_storage/downloading"
# Image blobs can have variants that are the result of a set of transformations applied to the original.
# These variants are used to create thumbnails, fixed-size avatars, or any other derivative image from the
# original.
@ -53,8 +51,6 @@
# * {ImageProcessing::Vips}[https://github.com/janko-m/image_processing/blob/master/doc/vips.md#methods]
# * {ruby-vips reference}[http://www.rubydoc.info/gems/ruby-vips/Vips/Image]
class ActiveStorage::Variant
include ActiveStorage::Downloading
WEB_IMAGE_CONTENT_TYPES = %w( image/png image/jpeg image/jpg image/gif )
attr_reader :blob, :variation
@ -98,7 +94,7 @@ def processed?
end
def process
download_blob_to_tempfile do |image|
blob.open do |image|
transform image do |output|
upload output
end

@ -1,13 +1,9 @@
# frozen_string_literal: true
require "active_storage/downloading"
module ActiveStorage
# This is an abstract base class for analyzers, which extract metadata from blobs. See
# ActiveStorage::Analyzer::ImageAnalyzer for an example of a concrete subclass.
class Analyzer
include Downloading
attr_reader :blob
# Implement this method in a concrete subclass. Have it return true when given a blob from which
@ -26,6 +22,11 @@ def metadata
end
private
# Downloads the blob to a tempfile on disk. Yields the tempfile.
def download_blob_to_tempfile #:doc:
blob.open(&block)
end
def logger #:doc:
ActiveStorage.logger
end

@ -0,0 +1,40 @@
# frozen_string_literal: true
module ActiveStorage
class Downloader
def initialize(blob)
@blob = blob
end
def download_blob_to_tempfile
open_tempfile do |file|
download_blob_to file
yield file
end
end
private
attr_reader :blob
def open_tempfile
file = Tempfile.open([ "ActiveStorage", tempfile_extension_with_delimiter ])
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 tempfile_extension_with_delimiter
blob.filename.extension_with_delimiter
end
end
end

@ -1,9 +1,17 @@
# frozen_string_literal: true
require "tmpdir"
require "active_support/core_ext/string/filters"
module ActiveStorage
module Downloading
def self.included(klass)
ActiveSupport::Deprecation.warn <<~MESSAGE.squish, caller_locations(2)
ActiveStorage::Downloading is deprecated and will be removed in Active Storage 6.1.
Use ActiveStorage::Blob#open instead.
MESSAGE
end
private
# Opens a new tempfile in #tempdir and copies blob data into it. Yields the tempfile.
def download_blob_to_tempfile #:doc:

@ -1,14 +1,12 @@
# frozen_string_literal: true
require "active_storage/downloading"
require "active_support/core_ext/string/filters"
module ActiveStorage
# This is an abstract base class for previewers, which generate images from blobs. See
# ActiveStorage::Previewer::PDFPreviewer and ActiveStorage::Previewer::VideoPreviewer for examples of
# concrete subclasses.
class Previewer
include Downloading
attr_reader :blob
# Implement this method in a concrete subclass. Have it return true when given a blob from which
@ -28,6 +26,11 @@ def preview
end
private
# Downloads the blob to a tempfile on disk. Yields the tempfile.
def download_blob_to_tempfile #:doc:
blob.open(&block)
end
# Executes a system command, capturing its binary output in a tempfile. Yields the tempfile.
#
# Use this method to shell out to a system library (e.g. mupdf or ffmpeg) for preview image

@ -84,6 +84,15 @@ class UserWithHasOneAttachedDependentFalse < User
assert_equal "a" * 64.kilobytes, chunks.second
end
test "open" do
create_file_blob(filename: "racecar.jpg").open do |file|
assert file.binmode?
assert_equal 0, file.pos
assert_match(/\.jpg\z/, file.path)
assert_equal file_fixture("racecar.jpg").binread, file.read, "Expected downloaded file to match fixture file"
end
end
test "urls expiring in 5 minutes" do
blob = create_blob