diff options
Diffstat (limited to 'activestorage')
-rw-r--r-- | activestorage/activestorage.gemspec | 3 | ||||
-rw-r--r-- | activestorage/app/models/active_storage/attachment.rb | 2 | ||||
-rw-r--r-- | activestorage/app/models/active_storage/blob.rb | 15 | ||||
-rw-r--r-- | activestorage/lib/active_storage.rb | 26 | ||||
-rw-r--r-- | activestorage/lib/active_storage/analyzer.rb | 4 | ||||
-rw-r--r-- | activestorage/lib/active_storage/downloader.rb | 29 | ||||
-rw-r--r-- | activestorage/lib/active_storage/engine.rb | 40 | ||||
-rw-r--r-- | activestorage/lib/active_storage/previewer.rb | 8 | ||||
-rw-r--r-- | activestorage/lib/active_storage/service.rb | 6 | ||||
-rw-r--r-- | activestorage/test/models/blob_test.rb | 8 |
10 files changed, 78 insertions, 63 deletions
diff --git a/activestorage/activestorage.gemspec b/activestorage/activestorage.gemspec index 34029ac8ad..0ae2dcdd3e 100644 --- a/activestorage/activestorage.gemspec +++ b/activestorage/activestorage.gemspec @@ -28,7 +28,8 @@ Gem::Specification.new do |s| # NOTE: Please read our dependency guidelines before updating versions: # https://edgeguides.rubyonrails.org/security.html#dependency-management-and-cves - s.add_dependency "actionpack", version + s.add_dependency "actionpack", version + s.add_dependency "activejob", version s.add_dependency "activerecord", version s.add_dependency "marcel", "~> 0.3.1" diff --git a/activestorage/app/models/active_storage/attachment.rb b/activestorage/app/models/active_storage/attachment.rb index 13758d9179..874ba80ca8 100644 --- a/activestorage/app/models/active_storage/attachment.rb +++ b/activestorage/app/models/active_storage/attachment.rb @@ -46,3 +46,5 @@ class ActiveStorage::Attachment < ActiveRecord::Base record.attachment_reflections[name]&.options[:dependent] end end + +ActiveSupport.run_load_hooks :active_storage_attachment, ActiveStorage::Attachment diff --git a/activestorage/app/models/active_storage/blob.rb b/activestorage/app/models/active_storage/blob.rb index 6ca7d49bc1..4da1605448 100644 --- a/activestorage/app/models/active_storage/blob.rb +++ b/activestorage/app/models/active_storage/blob.rb @@ -29,7 +29,7 @@ class ActiveStorage::Blob < ActiveRecord::Base has_secure_token :key store :metadata, accessors: [ :analyzed, :identified ], coder: ActiveRecord::Coders::JSON - class_attribute :service + class_attribute :service, default: ActiveStorage.service has_many :attachments @@ -193,17 +193,18 @@ class ActiveStorage::Blob < ActiveRecord::Base # # The tempfile's name is prefixed with +ActiveStorage-+ and the blob's ID. Its extension matches that of the blob. # - # By default, the tempfile is created in <tt>Dir.tmpdir</tt>. Pass +tempdir:+ to create it in a different directory: + # By default, the tempfile is created in <tt>Dir.tmpdir</tt>. Pass +tmpdir:+ to create it in a different directory: # - # blob.open(tempdir: "/path/to/tmp") do |file| + # blob.open(tmpdir: "/path/to/tmp") do |file| # # ... # end # # The tempfile is automatically closed and unlinked after the given block is executed. # # Raises ActiveStorage::IntegrityError if the downloaded data does not match the blob's checksum. - def open(tempdir: nil, &block) - ActiveStorage::Downloader.new(self, tempdir: tempdir).download_blob_to_tempfile(&block) + def open(tmpdir: nil, &block) + service.open key, checksum: checksum, + name: [ "ActiveStorage-#{id}-", filename.extension_with_delimiter ], tmpdir: tmpdir, &block end @@ -272,6 +273,6 @@ class ActiveStorage::Blob < ActiveRecord::Base { content_type: content_type } end end - - ActiveSupport.run_load_hooks(:active_storage_blob, self) end + +ActiveSupport.run_load_hooks :active_storage_blob, ActiveStorage::Blob diff --git a/activestorage/lib/active_storage.rb b/activestorage/lib/active_storage.rb index 5c5da551ae..c00c9f8037 100644 --- a/activestorage/lib/active_storage.rb +++ b/activestorage/lib/active_storage.rb @@ -41,19 +41,25 @@ module ActiveStorage autoload :Previewer autoload :Analyzer - mattr_accessor :logger - mattr_accessor :verifier - mattr_accessor :queues, default: {} - mattr_accessor :previewers, default: [] - mattr_accessor :analyzers, default: [] + mattr_accessor :service_configurations, default: {} + mattr_accessor :service + + mattr_accessor :queues, default: {} + mattr_accessor :previewers, default: [] + mattr_accessor :analyzers, default: [] mattr_accessor :variant_processor, default: :mini_magick - mattr_accessor :paths, default: {} - mattr_accessor :variable_content_types, default: [] + mattr_accessor :paths, default: {} + + mattr_accessor :variable_content_types, default: [] mattr_accessor :content_types_to_serve_as_binary, default: [] - mattr_accessor :content_types_allowed_inline, default: [] - mattr_accessor :binary_content_type, default: "application/octet-stream" + mattr_accessor :content_types_allowed_inline, default: [] + mattr_accessor :binary_content_type, default: "application/octet-stream" + mattr_accessor :service_urls_expire_in, default: 5.minutes - mattr_accessor :routes_prefix, default: "/rails/active_storage" + mattr_accessor :routes_prefix, default: "/rails/active_storage" + + mattr_accessor :logger + mattr_accessor :verifier module Transformers extend ActiveSupport::Autoload diff --git a/activestorage/lib/active_storage/analyzer.rb b/activestorage/lib/active_storage/analyzer.rb index caa25418a5..26414ffbc2 100644 --- a/activestorage/lib/active_storage/analyzer.rb +++ b/activestorage/lib/active_storage/analyzer.rb @@ -24,14 +24,14 @@ module ActiveStorage private # Downloads the blob to a tempfile on disk. Yields the tempfile. def download_blob_to_tempfile(&block) #:doc: - blob.open tempdir: tempdir, &block + blob.open tmpdir: tmpdir, &block end def logger #:doc: ActiveStorage.logger end - def tempdir #:doc: + def tmpdir #:doc: Dir.tmpdir end end diff --git a/activestorage/lib/active_storage/downloader.rb b/activestorage/lib/active_storage/downloader.rb index 87be6efb05..4d7e832af5 100644 --- a/activestorage/lib/active_storage/downloader.rb +++ b/activestorage/lib/active_storage/downloader.rb @@ -2,24 +2,23 @@ module ActiveStorage class Downloader #:nodoc: - def initialize(blob, tempdir: nil) - @blob = blob - @tempdir = tempdir + attr_reader :service + + def initialize(service) + @service = service end - def download_blob_to_tempfile - open_tempfile do |file| - download_blob_to file - verify_integrity_of file + def open(key, checksum:, name: "ActiveStorage-", tmpdir: nil) + open_tempfile(name, tmpdir) do |file| + download key, file + verify_integrity_of file, checksum: checksum yield file end end private - attr_reader :blob, :tempdir - - def open_tempfile - file = Tempfile.open([ "ActiveStorage-#{blob.id}-", blob.filename.extension_with_delimiter ], tempdir) + def open_tempfile(name, tmpdir = nil) + file = Tempfile.open(name, tmpdir) begin yield file @@ -28,15 +27,15 @@ module ActiveStorage end end - def download_blob_to(file) + def download(key, file) file.binmode - blob.download { |chunk| file.write(chunk) } + service.download(key) { |chunk| file.write(chunk) } file.flush file.rewind end - def verify_integrity_of(file) - unless Digest::MD5.file(file).base64digest == blob.checksum + def verify_integrity_of(file, checksum:) + unless Digest::MD5.file(file).base64digest == checksum raise ActiveStorage::IntegrityError end end diff --git a/activestorage/lib/active_storage/engine.rb b/activestorage/lib/active_storage/engine.rb index 384e6ebfa6..b27a027f3a 100644 --- a/activestorage/lib/active_storage/engine.rb +++ b/activestorage/lib/active_storage/engine.rb @@ -1,6 +1,10 @@ # frozen_string_literal: true require "rails" +require "action_controller/railtie" +require "active_job/railtie" +require "active_record/railtie" + require "active_storage" require "active_storage/previewer/poppler_pdf_previewer" @@ -91,25 +95,25 @@ module ActiveStorage end initializer "active_storage.services" do - ActiveSupport.on_load(:active_storage_blob) do - if config_choice = Rails.configuration.active_storage.service - configs = Rails.configuration.active_storage.service_configurations ||= begin - config_file = Pathname.new(Rails.root.join("config/storage.yml")) - raise("Couldn't find Active Storage configuration in #{config_file}") unless config_file.exist? - - require "yaml" - require "erb" - - YAML.load(ERB.new(config_file.read).result) || {} - rescue Psych::SyntaxError => e - raise "YAML syntax error occurred while parsing #{config_file}. " \ - "Please note that YAML must be consistently indented using spaces. Tabs are not allowed. " \ - "Error: #{e.message}" - end - - ActiveStorage::Blob.service = + config.after_initialize do |app| + ActiveStorage.service_configurations = begin + config_file = Pathname.new(Rails.root.join("config/storage.yml")) + raise("Couldn't find Active Storage configuration in #{config_file}") unless config_file.exist? + + require "yaml" + require "erb" + + YAML.load(ERB.new(config_file.read).result) || {} + rescue Psych::SyntaxError => e + raise "YAML syntax error occurred while parsing #{config_file}. " \ + "Please note that YAML must be consistently indented using spaces. Tabs are not allowed. " \ + "Error: #{e.message}" + end + + if global_service_name = app.config.active_storage.service + ActiveStorage.service = begin - ActiveStorage::Service.configure config_choice, configs + ActiveStorage::Service.configure(global_service_name) rescue => e raise e, "Cannot load `Rails.config.active_storage.service`:\n#{e.message}", e.backtrace end diff --git a/activestorage/lib/active_storage/previewer.rb b/activestorage/lib/active_storage/previewer.rb index 95a041fd16..af6bcadd4c 100644 --- a/activestorage/lib/active_storage/previewer.rb +++ b/activestorage/lib/active_storage/previewer.rb @@ -26,7 +26,7 @@ module ActiveStorage private # Downloads the blob to a tempfile on disk. Yields the tempfile. def download_blob_to_tempfile(&block) #:doc: - blob.open tempdir: tempdir, &block + blob.open tmpdir: tmpdir, &block end # Executes a system command, capturing its binary output in a tempfile. Yields the tempfile. @@ -42,7 +42,7 @@ module ActiveStorage # end # end # - # The output tempfile is opened in the directory returned by #tempdir. + # The output tempfile is opened in the directory returned by #tmpdir. def draw(*argv) #:doc: open_tempfile do |file| instrument :preview, key: blob.key do @@ -54,7 +54,7 @@ module ActiveStorage end def open_tempfile - tempfile = Tempfile.open("ActiveStorage-", tempdir) + tempfile = Tempfile.open("ActiveStorage-", tmpdir) begin yield tempfile @@ -77,7 +77,7 @@ module ActiveStorage ActiveStorage.logger end - def tempdir #:doc: + def tmpdir #:doc: Dir.tmpdir end end diff --git a/activestorage/lib/active_storage/service.rb b/activestorage/lib/active_storage/service.rb index c18fccbb1d..f0d04153a1 100644 --- a/activestorage/lib/active_storage/service.rb +++ b/activestorage/lib/active_storage/service.rb @@ -45,7 +45,7 @@ module ActiveStorage # Configure an Active Storage service by name from a set of configurations, # typically loaded from a YAML file. The Active Storage engine uses this # to set the global Active Storage service when the app boots. - def configure(service_name, configurations) + def configure(service_name, configurations = ActiveStorage.service_configurations) Configurator.build(service_name, configurations) end @@ -82,6 +82,10 @@ module ActiveStorage raise NotImplementedError end + def open(*args, &block) + ActiveStorage::Downloader.new(self).open(*args, &block) + end + # Delete the file at the +key+. def delete(key) raise NotImplementedError diff --git a/activestorage/test/models/blob_test.rb b/activestorage/test/models/blob_test.rb index 54cf9e2b8a..b7b37bacf5 100644 --- a/activestorage/test/models/blob_test.rb +++ b/activestorage/test/models/blob_test.rb @@ -104,14 +104,12 @@ class ActiveStorage::BlobTest < ActiveSupport::TestCase end end - test "open in a custom tempdir" do - tempdir = Dir.mktmpdir - - create_file_blob(filename: "racecar.jpg").open(tempdir: tempdir) do |file| + test "open in a custom tmpdir" do + create_file_blob(filename: "racecar.jpg").open(tmpdir: tmpdir = Dir.mktmpdir) do |file| assert file.binmode? assert_equal 0, file.pos assert_match(/\.jpg\z/, file.path) - assert file.path.starts_with?(tempdir) + assert file.path.starts_with?(tmpdir) assert_equal file_fixture("racecar.jpg").binread, file.read, "Expected downloaded file to match fixture file" end end |