aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--activestorage/app/models/active_storage/blob.rb26
-rw-r--r--activestorage/app/models/active_storage/variant.rb4
-rw-r--r--activestorage/test/models/preview_test.rb2
-rw-r--r--activestorage/test/models/representation_test.rb41
4 files changed, 73 insertions, 0 deletions
diff --git a/activestorage/app/models/active_storage/blob.rb b/activestorage/app/models/active_storage/blob.rb
index ff785d4f61..d43049e32c 100644
--- a/activestorage/app/models/active_storage/blob.rb
+++ b/activestorage/app/models/active_storage/blob.rb
@@ -15,6 +15,7 @@
# If you need to create a derivative or otherwise change the blob, simply create a new blob and purge the old one.
class ActiveStorage::Blob < ActiveRecord::Base
class UnpreviewableError < StandardError; end
+ class UnrepresentableError < StandardError; end
self.table_name = "active_storage_blobs"
@@ -155,6 +156,31 @@ class ActiveStorage::Blob < ActiveRecord::Base
end
+ # Returns an ActiveStorage::Preview instance for a previewable blob or an ActiveStorage::Variant instance for an image blob.
+ #
+ # blob.representation(resize: "100x100").processed.service_url
+ #
+ # Raises ActiveStorage::Blob::UnrepresentableError if the receiving blob is neither an image nor previewable. Call
+ # ActiveStorage::Blob#representable? to determine whether a blob is representable.
+ #
+ # See ActiveStorage::Blob#preview and ActiveStorage::Blob#variant for more information.
+ def representation(transformations)
+ case
+ when previewable?
+ preview transformations
+ when image?
+ variant transformations
+ else
+ raise UnrepresentableError
+ end
+ end
+
+ # Returns true if the blob is an image or is previewable.
+ def representable?
+ image? || previewable?
+ end
+
+
# Returns the URL of the blob on the service. This URL is intended to be short-lived for security and not used directly
# with users. Instead, the +service_url+ should only be exposed as a redirect from a stable, possibly authenticated URL.
# Hiding the +service_url+ behind a redirect also gives you the power to change services without updating all URLs. And
diff --git a/activestorage/app/models/active_storage/variant.rb b/activestorage/app/models/active_storage/variant.rb
index 90a3605331..915b78162c 100644
--- a/activestorage/app/models/active_storage/variant.rb
+++ b/activestorage/app/models/active_storage/variant.rb
@@ -65,6 +65,10 @@ class ActiveStorage::Variant
service.url key, expires_in: expires_in, disposition: disposition, filename: blob.filename, content_type: blob.content_type
end
+ # Returns the receiving variant. Allows ActiveStorage::Variant and ActiveStorage::Preview instances to be duck-typed.
+ def image
+ self
+ end
private
def processed?
diff --git a/activestorage/test/models/preview_test.rb b/activestorage/test/models/preview_test.rb
index 317a2d5c58..bcd8442f4b 100644
--- a/activestorage/test/models/preview_test.rb
+++ b/activestorage/test/models/preview_test.rb
@@ -7,6 +7,7 @@ class ActiveStorage::PreviewTest < ActiveSupport::TestCase
test "previewing a PDF" do
blob = create_file_blob(filename: "report.pdf", content_type: "application/pdf")
preview = blob.preview(resize: "640x280").processed
+
assert preview.image.attached?
assert_equal "report.png", preview.image.filename.to_s
assert_equal "image/png", preview.image.content_type
@@ -19,6 +20,7 @@ class ActiveStorage::PreviewTest < ActiveSupport::TestCase
test "previewing an MP4 video" do
blob = create_file_blob(filename: "video.mp4", content_type: "video/mp4")
preview = blob.preview(resize: "640x280").processed
+
assert preview.image.attached?
assert_equal "video.png", preview.image.filename.to_s
assert_equal "image/png", preview.image.content_type
diff --git a/activestorage/test/models/representation_test.rb b/activestorage/test/models/representation_test.rb
new file mode 100644
index 0000000000..29fe61aee4
--- /dev/null
+++ b/activestorage/test/models/representation_test.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+require "test_helper"
+require "database/setup"
+
+class ActiveStorage::RepresentationTest < ActiveSupport::TestCase
+ test "representing an image" do
+ blob = create_file_blob
+ representation = blob.representation(resize: "100x100").processed
+
+ image = read_image(representation.image)
+ assert_equal 100, image.width
+ assert_equal 67, image.height
+ end
+
+ test "representing a PDF" do
+ blob = create_file_blob(filename: "report.pdf", content_type: "application/pdf")
+ representation = blob.representation(resize: "640x280").processed
+
+ image = read_image(representation.image)
+ assert_equal 612, image.width
+ assert_equal 792, image.height
+ end
+
+ test "representing an MP4 video" do
+ blob = create_file_blob(filename: "video.mp4", content_type: "video/mp4")
+ representation = blob.representation(resize: "640x280").processed
+
+ image = read_image(representation.image)
+ assert_equal 640, image.width
+ assert_equal 480, image.height
+ end
+
+ test "representing an unrepresentable blob" do
+ blob = create_blob
+
+ assert_raises ActiveStorage::Blob::UnrepresentableError do
+ blob.representation resize: "100x100"
+ end
+ end
+end