diff options
Diffstat (limited to 'activestorage/app/models/active_storage')
7 files changed, 46 insertions, 14 deletions
diff --git a/activestorage/app/models/active_storage/blob.rb b/activestorage/app/models/active_storage/blob.rb index 892a833fae..0cd4ad8128 100644 --- a/activestorage/app/models/active_storage/blob.rb +++ b/activestorage/app/models/active_storage/blob.rb @@ -14,7 +14,13 @@ # update a blob's metadata on a subsequent pass, but you should not update the key or change the uploaded file. # 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 - include Analyzable, Identifiable, Representable + require_dependency "active_storage/blob/analyzable" + require_dependency "active_storage/blob/identifiable" + require_dependency "active_storage/blob/representable" + + include Analyzable + include Identifiable + include Representable self.table_name = "active_storage_blobs" @@ -25,6 +31,8 @@ class ActiveStorage::Blob < ActiveRecord::Base has_many :attachments + scope :unattached, -> { left_joins(:attachments).where(ActiveStorage::Attachment.table_name => { blob_id: nil }) } + class << self # You can used the signed ID of a blob to refer to it on the client side without fear of tampering. # This is particularly helpful for direct uploads where the client-side needs to refer to the blob @@ -109,7 +117,9 @@ class ActiveStorage::Blob < ActiveRecord::Base # 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 # it allows permanent URLs that redirect to the +service_url+ to be cached in the view. - def service_url(expires_in: service.url_expires_in, disposition: :inline, filename: self.filename, **options) + def service_url(expires_in: service.url_expires_in, disposition: :inline, filename: nil, **options) + filename = ActiveStorage::Filename.wrap(filename || self.filename) + service.url key, expires_in: expires_in, filename: filename, content_type: content_type, disposition: forcibly_serve_as_binary? ? :attachment : disposition, **options end @@ -192,4 +202,6 @@ class ActiveStorage::Blob < ActiveRecord::Base def forcibly_serve_as_binary? ActiveStorage.content_types_to_serve_as_binary.include?(content_type) end + + ActiveSupport.run_load_hooks(:active_storage_blob, self) end diff --git a/activestorage/app/models/active_storage/blob/identifiable.rb b/activestorage/app/models/active_storage/blob/identifiable.rb index 40ca84ac70..dbe03cfa6c 100644 --- a/activestorage/app/models/active_storage/blob/identifiable.rb +++ b/activestorage/app/models/active_storage/blob/identifiable.rb @@ -2,10 +2,15 @@ module ActiveStorage::Blob::Identifiable def identify - ActiveStorage::Identification.new(self).apply + update!(content_type: identification.content_type, identified: true) unless identified? end def identified? identified end + + private + def identification + ActiveStorage::Identification.new self + end end diff --git a/activestorage/app/models/active_storage/filename.rb b/activestorage/app/models/active_storage/filename.rb index b9413dec95..bebb5e61b3 100644 --- a/activestorage/app/models/active_storage/filename.rb +++ b/activestorage/app/models/active_storage/filename.rb @@ -3,8 +3,18 @@ # Encapsulates a string representing a filename to provide convenient access to parts of it and sanitization. # A Filename instance is returned by ActiveStorage::Blob#filename, and is comparable so it can be used for sorting. class ActiveStorage::Filename + require_dependency "active_storage/filename/parameters" + include Comparable + class << self + # Returns a Filename instance based on the given filename. If the filename is a Filename, it is + # returned unmodified. If it is a String, it is passed to ActiveStorage::Filename.new. + def wrap(filename) + filename.kind_of?(self) ? filename : new(filename) + end + end + def initialize(filename) @filename = filename end diff --git a/activestorage/app/models/active_storage/identification.rb b/activestorage/app/models/active_storage/identification.rb index 4f295257ae..8d334ae1ea 100644 --- a/activestorage/app/models/active_storage/identification.rb +++ b/activestorage/app/models/active_storage/identification.rb @@ -1,25 +1,22 @@ # frozen_string_literal: true -class ActiveStorage::Identification +require "net/http" + +class ActiveStorage::Identification #:nodoc: attr_reader :blob def initialize(blob) @blob = blob end - def apply - blob.update!(content_type: content_type, identified: true) unless blob.identified? + def content_type + Marcel::MimeType.for(identifiable_chunk, name: filename, declared_type: declared_content_type) end private - def content_type - Marcel::MimeType.for(identifiable_chunk, name: filename, declared_type: declared_content_type) - end - - def identifiable_chunk Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == "https") do |client| - client.get(uri, "Range" => "0-4096").body + client.get(uri, "Range" => "bytes=0-4095").body end end diff --git a/activestorage/app/models/active_storage/preview.rb b/activestorage/app/models/active_storage/preview.rb index be5053edae..45efd26214 100644 --- a/activestorage/app/models/active_storage/preview.rb +++ b/activestorage/app/models/active_storage/preview.rb @@ -24,7 +24,7 @@ # The built-in previewers rely on third-party system libraries: # # * {ffmpeg}[https://www.ffmpeg.org] -# * {mupdf}[https://mupdf.com] +# * {mupdf}[https://mupdf.com] (version 1.8 or newer) # # These libraries are not provided by Rails. You must install them yourself to use the built-in previewers. Before you # install and use third-party software, make sure you understand the licensing implications of doing so. diff --git a/activestorage/app/models/active_storage/variant.rb b/activestorage/app/models/active_storage/variant.rb index e08a2271ec..a95a4bfd7c 100644 --- a/activestorage/app/models/active_storage/variant.rb +++ b/activestorage/app/models/active_storage/variant.rb @@ -115,7 +115,7 @@ class ActiveStorage::Variant def download_image require "mini_magick" - MiniMagick::Image.create { |file| download_blob_to(file) } + MiniMagick::Image.create(blob.filename.extension_with_delimiter) { |file| download_blob_to(file) } end def transform(image) diff --git a/activestorage/app/models/active_storage/variation.rb b/activestorage/app/models/active_storage/variation.rb index da4af62666..12e7f9f0b5 100644 --- a/activestorage/app/models/active_storage/variation.rb +++ b/activestorage/app/models/active_storage/variation.rb @@ -8,6 +8,14 @@ # # ActiveStorage::Variation.new(resize: "100x100", monochrome: true, trim: true, rotate: "-90") # +# You can also combine multiple transformations in one step, e.g. for center-weighted cropping: +# +# ActiveStorage::Variation.new(combine_options: { +# resize: "100x100^", +# gravity: "center", +# crop: "100x100+0+0", +# }) +# # A list of all possible transformations is available at https://www.imagemagick.org/script/mogrify.php. class ActiveStorage::Variation attr_reader :transformations |