Permalink
Browse files

Add ActiveStorage::Blob#open

[David Robertson & George Claghorn]
  • Loading branch information...
georgeclaghorn committed May 17, 2018
1 parent bfe4248 commit ee21b7c2eb64def8f00887a9fafbd77b85f464f1
@@ -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

0 comments on commit ee21b7c

Please sign in to comment.