aboutsummaryrefslogtreecommitdiffstats
path: root/activestorage/lib/active_storage
diff options
context:
space:
mode:
Diffstat (limited to 'activestorage/lib/active_storage')
-rw-r--r--activestorage/lib/active_storage/analyzer/video_analyzer.rb4
-rw-r--r--activestorage/lib/active_storage/attached/macros.rb8
-rw-r--r--activestorage/lib/active_storage/attached/many.rb12
-rw-r--r--activestorage/lib/active_storage/attached/one.rb23
-rw-r--r--activestorage/lib/active_storage/engine.rb19
-rw-r--r--activestorage/lib/active_storage/gem_version.rb2
-rw-r--r--activestorage/lib/active_storage/log_subscriber.rb4
-rw-r--r--activestorage/lib/active_storage/previewer.rb4
-rw-r--r--activestorage/lib/active_storage/previewer/pdf_previewer.rb9
-rw-r--r--activestorage/lib/active_storage/previewer/video_previewer.rb4
-rw-r--r--activestorage/lib/active_storage/service.rb9
-rw-r--r--activestorage/lib/active_storage/service/azure_storage_service.rb38
-rw-r--r--activestorage/lib/active_storage/service/disk_service.rb22
-rw-r--r--activestorage/lib/active_storage/service/gcs_service.rb45
-rw-r--r--activestorage/lib/active_storage/service/mirror_service.rb5
-rw-r--r--activestorage/lib/active_storage/service/s3_service.rb26
16 files changed, 175 insertions, 59 deletions
diff --git a/activestorage/lib/active_storage/analyzer/video_analyzer.rb b/activestorage/lib/active_storage/analyzer/video_analyzer.rb
index 408b5e58e9..b6fc54d917 100644
--- a/activestorage/lib/active_storage/analyzer/video_analyzer.rb
+++ b/activestorage/lib/active_storage/analyzer/video_analyzer.rb
@@ -19,6 +19,8 @@ module ActiveStorage
# This analyzer requires the {ffmpeg}[https://www.ffmpeg.org] system library, which is not provided by Rails. You must
# install ffmpeg yourself to use this analyzer.
class Analyzer::VideoAnalyzer < Analyzer
+ class_attribute :ffprobe_path, default: "ffprobe"
+
def self.accept?(blob)
blob.video?
end
@@ -68,7 +70,7 @@ module ActiveStorage
end
def probe_from(file)
- IO.popen([ "ffprobe", "-print_format", "json", "-show_streams", "-v", "error", file.path ]) do |output|
+ IO.popen([ ffprobe_path, "-print_format", "json", "-show_streams", "-v", "error", file.path ]) do |output|
JSON.parse(output.read)
end
rescue Errno::ENOENT
diff --git a/activestorage/lib/active_storage/attached/macros.rb b/activestorage/lib/active_storage/attached/macros.rb
index f0256718ac..2b38a9b887 100644
--- a/activestorage/lib/active_storage/attached/macros.rb
+++ b/activestorage/lib/active_storage/attached/macros.rb
@@ -32,6 +32,10 @@ module ActiveStorage
def #{name}
@active_storage_attached_#{name} ||= ActiveStorage::Attached::One.new("#{name}", self, dependent: #{dependent == :purge_later ? ":purge_later" : "false"})
end
+
+ def #{name}=(attachable)
+ #{name}.attach(attachable)
+ end
CODE
has_one :"#{name}_attachment", -> { where(name: name) }, class_name: "ActiveStorage::Attachment", as: :record
@@ -73,6 +77,10 @@ module ActiveStorage
def #{name}
@active_storage_attached_#{name} ||= ActiveStorage::Attached::Many.new("#{name}", self, dependent: #{dependent == :purge_later ? ":purge_later" : "false"})
end
+
+ def #{name}=(attachables)
+ #{name}.attach(attachables)
+ end
CODE
has_many :"#{name}_attachments", -> { where(name: name) }, as: :record, class_name: "ActiveStorage::Attachment"
diff --git a/activestorage/lib/active_storage/attached/many.rb b/activestorage/lib/active_storage/attached/many.rb
index 1e0657c33c..6eace65b79 100644
--- a/activestorage/lib/active_storage/attached/many.rb
+++ b/activestorage/lib/active_storage/attached/many.rb
@@ -13,7 +13,6 @@ module ActiveStorage
end
# Associates one or several attachments with the current record, saving them to the database.
- # Examples:
#
# document.images.attach(params[:images]) # Array of ActionDispatch::Http::UploadedFile objects
# document.images.attach(params[:signed_blob_id]) # Signed reference to blob from direct upload
@@ -21,7 +20,11 @@ module ActiveStorage
# document.images.attach([ first_blob, second_blob ])
def attach(*attachables)
attachables.flatten.collect do |attachable|
- attachments.create!(name: name, blob: create_blob_from(attachable))
+ if record.new_record?
+ attachments.build(record: record, blob: create_blob_from(attachable))
+ else
+ attachments.create!(record: record, blob: create_blob_from(attachable))
+ end
end
end
@@ -36,6 +39,11 @@ module ActiveStorage
attachments.any?
end
+ # Deletes associated attachments without purging them, leaving their respective blobs in place.
+ def detach
+ attachments.destroy_all if attached?
+ end
+
# Directly purges each associated attachment (i.e. destroys the blobs and
# attachments and deletes the files on the service).
def purge
diff --git a/activestorage/lib/active_storage/attached/one.rb b/activestorage/lib/active_storage/attached/one.rb
index dc19512484..0244232b2c 100644
--- a/activestorage/lib/active_storage/attached/one.rb
+++ b/activestorage/lib/active_storage/attached/one.rb
@@ -14,7 +14,6 @@ module ActiveStorage
end
# Associates a given attachment with the current record, saving it to the database.
- # Examples:
#
# person.avatar.attach(params[:avatar]) # ActionDispatch::Http::UploadedFile object
# person.avatar.attach(params[:signed_blob_id]) # Signed reference to blob from direct upload
@@ -24,7 +23,7 @@ module ActiveStorage
if attached? && dependent == :purge_later
replace attachable
else
- write_attachment create_attachment_from(attachable)
+ write_attachment build_attachment_from(attachable)
end
end
@@ -39,6 +38,14 @@ module ActiveStorage
attachment.present?
end
+ # Deletes the attachment without purging it, leaving its blob in place.
+ def detach
+ if attached?
+ attachment.destroy
+ write_attachment nil
+ end
+ end
+
# Directly purges the attachment (i.e. destroys the blob and
# attachment and deletes the file on the service).
def purge
@@ -59,18 +66,14 @@ module ActiveStorage
def replace(attachable)
blob.tap do
transaction do
- destroy_attachment
- write_attachment create_attachment_from(attachable)
+ detach
+ write_attachment build_attachment_from(attachable)
end
end.purge_later
end
- def destroy_attachment
- attachment.destroy
- end
-
- def create_attachment_from(attachable)
- ActiveStorage::Attachment.create!(record: record, name: name, blob: create_blob_from(attachable))
+ def build_attachment_from(attachable)
+ ActiveStorage::Attachment.new(record: record, name: name, blob: create_blob_from(attachable))
end
def write_attachment(attachment)
diff --git a/activestorage/lib/active_storage/engine.rb b/activestorage/lib/active_storage/engine.rb
index 6cf6635c4f..b870e6d4d6 100644
--- a/activestorage/lib/active_storage/engine.rb
+++ b/activestorage/lib/active_storage/engine.rb
@@ -15,7 +15,8 @@ module ActiveStorage
config.active_storage = ActiveSupport::OrderedOptions.new
config.active_storage.previewers = [ ActiveStorage::Previewer::PDFPreviewer, ActiveStorage::Previewer::VideoPreviewer ]
- config.active_storage.analyzers = [ ActiveStorage::Analyzer::ImageAnalyzer, ActiveStorage::Analyzer::VideoAnalyzer ]
+ config.active_storage.analyzers = [ ActiveStorage::Analyzer::ImageAnalyzer, ActiveStorage::Analyzer::VideoAnalyzer ]
+ config.active_storage.paths = ActiveSupport::OrderedOptions.new
config.eager_load_namespaces << ActiveStorage
@@ -68,5 +69,21 @@ module ActiveStorage
end
end
end
+
+ initializer "active_storage.paths" do
+ config.after_initialize do |app|
+ if ffprobe_path = app.config.active_storage.paths.ffprobe
+ ActiveStorage::Analyzer::VideoAnalyzer.ffprobe_path = ffprobe_path
+ end
+
+ if ffmpeg_path = app.config.active_storage.paths.ffmpeg
+ ActiveStorage::Previewer::VideoPreviewer.ffmpeg_path = ffmpeg_path
+ end
+
+ if mutool_path = app.config.active_storage.paths.mutool
+ ActiveStorage::Previewer::PDFPreviewer.mutool_path = mutool_path
+ end
+ end
+ end
end
end
diff --git a/activestorage/lib/active_storage/gem_version.rb b/activestorage/lib/active_storage/gem_version.rb
index e1d7b3493a..f048bb0b77 100644
--- a/activestorage/lib/active_storage/gem_version.rb
+++ b/activestorage/lib/active_storage/gem_version.rb
@@ -10,7 +10,7 @@ module ActiveStorage
MAJOR = 5
MINOR = 2
TINY = 0
- PRE = "alpha"
+ PRE = "beta2"
STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
end
diff --git a/activestorage/lib/active_storage/log_subscriber.rb b/activestorage/lib/active_storage/log_subscriber.rb
index 5cbf4bd1a5..a4e148c1a5 100644
--- a/activestorage/lib/active_storage/log_subscriber.rb
+++ b/activestorage/lib/active_storage/log_subscriber.rb
@@ -18,6 +18,10 @@ module ActiveStorage
info event, color("Deleted file from key: #{key_in(event)}", RED)
end
+ def service_delete_prefixed(event)
+ info event, color("Deleted files by key prefix: #{event.payload[:prefix]}", RED)
+ end
+
def service_exist(event)
debug event, color("Checked if file exists at key: #{key_in(event)} (#{event.payload[:exist] ? "yes" : "no"})", BLUE)
end
diff --git a/activestorage/lib/active_storage/previewer.rb b/activestorage/lib/active_storage/previewer.rb
index ed75bae3b5..3d485988e9 100644
--- a/activestorage/lib/active_storage/previewer.rb
+++ b/activestorage/lib/active_storage/previewer.rb
@@ -54,5 +54,9 @@ module ActiveStorage
IO.popen(argv) { |out| IO.copy_stream(out, to) }
to.rewind
end
+
+ def logger
+ ActiveStorage.logger
+ end
end
end
diff --git a/activestorage/lib/active_storage/previewer/pdf_previewer.rb b/activestorage/lib/active_storage/previewer/pdf_previewer.rb
index a2f05c74a6..b84aefcc9c 100644
--- a/activestorage/lib/active_storage/previewer/pdf_previewer.rb
+++ b/activestorage/lib/active_storage/previewer/pdf_previewer.rb
@@ -2,16 +2,23 @@
module ActiveStorage
class Previewer::PDFPreviewer < Previewer
+ class_attribute :mutool_path, default: "mutool"
+
def self.accept?(blob)
blob.content_type == "application/pdf"
end
def preview
download_blob_to_tempfile do |input|
- draw "mutool", "draw", "-F", "png", "-o", "-", input.path, "1" do |output|
+ draw_first_page_from input do |output|
yield io: output, filename: "#{blob.filename.base}.png", content_type: "image/png"
end
end
end
+
+ private
+ def draw_first_page_from(file, &block)
+ draw mutool_path, "draw", "-F", "png", "-o", "-", file.path, "1", &block
+ end
end
end
diff --git a/activestorage/lib/active_storage/previewer/video_previewer.rb b/activestorage/lib/active_storage/previewer/video_previewer.rb
index 49f128d142..5d06e33f44 100644
--- a/activestorage/lib/active_storage/previewer/video_previewer.rb
+++ b/activestorage/lib/active_storage/previewer/video_previewer.rb
@@ -2,6 +2,8 @@
module ActiveStorage
class Previewer::VideoPreviewer < Previewer
+ class_attribute :ffmpeg_path, default: "ffmpeg"
+
def self.accept?(blob)
blob.video?
end
@@ -16,7 +18,7 @@ module ActiveStorage
private
def draw_relevant_frame_from(file, &block)
- draw "ffmpeg", "-i", file.path, "-y", "-vcodec", "png",
+ draw ffmpeg_path, "-i", file.path, "-y", "-vcodec", "png",
"-vf", "thumbnail", "-vframes", "1", "-f", "image2", "-", &block
end
end
diff --git a/activestorage/lib/active_storage/service.rb b/activestorage/lib/active_storage/service.rb
index aa150e4d8a..c8f675db86 100644
--- a/activestorage/lib/active_storage/service.rb
+++ b/activestorage/lib/active_storage/service.rb
@@ -78,6 +78,11 @@ module ActiveStorage
raise NotImplementedError
end
+ # Delete files at keys starting with the +prefix+.
+ def delete_prefixed(prefix)
+ raise NotImplementedError
+ end
+
# Return +true+ if a file exists at the +key+.
def exist?(key)
raise NotImplementedError
@@ -104,10 +109,10 @@ module ActiveStorage
end
private
- def instrument(operation, key, payload = {}, &block)
+ def instrument(operation, payload = {}, &block)
ActiveSupport::Notifications.instrument(
"service_#{operation}.active_storage",
- payload.merge(key: key, service: service_name), &block)
+ payload.merge(service: service_name), &block)
end
def service_name
diff --git a/activestorage/lib/active_storage/service/azure_storage_service.rb b/activestorage/lib/active_storage/service/azure_storage_service.rb
index 27dd192ce6..19b09991b3 100644
--- a/activestorage/lib/active_storage/service/azure_storage_service.rb
+++ b/activestorage/lib/active_storage/service/azure_storage_service.rb
@@ -19,7 +19,7 @@ module ActiveStorage
end
def upload(key, io, checksum: nil)
- instrument :upload, key, checksum: checksum do
+ instrument :upload, key: key, checksum: checksum do
begin
blobs.create_block_blob(container, key, io, content_md5: checksum)
rescue Azure::Core::Http::HTTPError
@@ -28,13 +28,13 @@ module ActiveStorage
end
end
- def download(key)
+ def download(key, &block)
if block_given?
- instrument :streaming_download, key do
+ instrument :streaming_download, key: key do
stream(key, &block)
end
else
- instrument :download, key do
+ instrument :download, key: key do
_, io = blobs.get_blob(container, key)
io.force_encoding(Encoding::BINARY)
end
@@ -42,7 +42,7 @@ module ActiveStorage
end
def delete(key)
- instrument :delete, key do
+ instrument :delete, key: key do
begin
blobs.delete_blob(container, key)
rescue Azure::Core::Http::HTTPError
@@ -51,8 +51,24 @@ module ActiveStorage
end
end
+ def delete_prefixed(prefix)
+ instrument :delete_prefixed, prefix: prefix do
+ marker = nil
+
+ loop do
+ results = blobs.list_blobs(container, prefix: prefix, marker: marker)
+
+ results.each do |blob|
+ blobs.delete_blob(container, blob.name)
+ end
+
+ break unless marker = results.continuation_token.presence
+ end
+ end
+ end
+
def exist?(key)
- instrument :exist, key do |payload|
+ instrument :exist, key: key do |payload|
answer = blob_for(key).present?
payload[:exist] = answer
answer
@@ -60,7 +76,7 @@ module ActiveStorage
end
def url(key, expires_in:, filename:, disposition:, content_type:)
- instrument :url, key do |payload|
+ instrument :url, key: key do |payload|
base_url = url_for(key)
generated_url = signer.signed_uri(
URI(base_url), false,
@@ -77,7 +93,7 @@ module ActiveStorage
end
def url_for_direct_upload(key, expires_in:, content_type:, content_length:, checksum:)
- instrument :url, key do |payload|
+ instrument :url, key: key do |payload|
base_url = url_for(key)
generated_url = signer.signed_uri(URI(base_url), false, permissions: "rw",
expiry: format_expiry(expires_in)).to_s
@@ -108,15 +124,15 @@ module ActiveStorage
end
# Reads the object for the given key in chunks, yielding each to the block.
- def stream(key, options = {}, &block)
+ def stream(key)
blob = blob_for(key)
chunk_size = 5.megabytes
offset = 0
while offset < blob.properties[:content_length]
- _, io = blobs.get_blob(container, key, start_range: offset, end_range: offset + chunk_size - 1)
- yield io
+ _, chunk = blobs.get_blob(container, key, start_range: offset, end_range: offset + chunk_size - 1)
+ yield chunk.force_encoding(Encoding::BINARY)
offset += chunk_size
end
end
diff --git a/activestorage/lib/active_storage/service/disk_service.rb b/activestorage/lib/active_storage/service/disk_service.rb
index 52eaba4e7b..a8728c5bc3 100644
--- a/activestorage/lib/active_storage/service/disk_service.rb
+++ b/activestorage/lib/active_storage/service/disk_service.rb
@@ -16,7 +16,7 @@ module ActiveStorage
end
def upload(key, io, checksum: nil)
- instrument :upload, key, checksum: checksum do
+ instrument :upload, key: key, checksum: checksum do
IO.copy_stream(io, make_path_for(key))
ensure_integrity_of(key, checksum) if checksum
end
@@ -24,7 +24,7 @@ module ActiveStorage
def download(key)
if block_given?
- instrument :streaming_download, key do
+ instrument :streaming_download, key: key do
File.open(path_for(key), "rb") do |file|
while data = file.read(64.kilobytes)
yield data
@@ -32,14 +32,14 @@ module ActiveStorage
end
end
else
- instrument :download, key do
+ instrument :download, key: key do
File.binread path_for(key)
end
end
end
def delete(key)
- instrument :delete, key do
+ instrument :delete, key: key do
begin
File.delete path_for(key)
rescue Errno::ENOENT
@@ -48,8 +48,16 @@ module ActiveStorage
end
end
+ def delete_prefixed(prefix)
+ instrument :delete_prefixed, prefix: prefix do
+ Dir.glob(path_for("#{prefix}*")).each do |path|
+ FileUtils.rm_rf(path)
+ end
+ end
+ end
+
def exist?(key)
- instrument :exist, key do |payload|
+ instrument :exist, key: key do |payload|
answer = File.exist? path_for(key)
payload[:exist] = answer
answer
@@ -57,7 +65,7 @@ module ActiveStorage
end
def url(key, expires_in:, filename:, disposition:, content_type:)
- instrument :url, key do |payload|
+ instrument :url, key: key do |payload|
verified_key_with_expiration = ActiveStorage.verifier.generate(key, expires_in: expires_in, purpose: :blob_key)
generated_url =
@@ -77,7 +85,7 @@ module ActiveStorage
end
def url_for_direct_upload(key, expires_in:, content_type:, content_length:, checksum:)
- instrument :url, key do |payload|
+ instrument :url, key: key do |payload|
verified_token_with_expiration = ActiveStorage.verifier.generate(
{
key: key,
diff --git a/activestorage/lib/active_storage/service/gcs_service.rb b/activestorage/lib/active_storage/service/gcs_service.rb
index b4ffeeeb8a..6f6f4105fe 100644
--- a/activestorage/lib/active_storage/service/gcs_service.rb
+++ b/activestorage/lib/active_storage/service/gcs_service.rb
@@ -1,5 +1,7 @@
# frozen_string_literal: true
+gem "google-cloud-storage", "~> 1.8"
+
require "google/cloud/storage"
require "active_support/core_ext/object/to_query"
@@ -7,17 +9,20 @@ module ActiveStorage
# Wraps the Google Cloud Storage as an Active Storage service. See ActiveStorage::Service for the generic API
# documentation that applies to all services.
class Service::GCSService < Service
- attr_reader :client, :bucket
-
- def initialize(project:, keyfile:, bucket:, **options)
- @client = Google::Cloud::Storage.new(project: project, keyfile: keyfile, **options)
- @bucket = @client.bucket(bucket)
+ def initialize(**config)
+ @config = config
end
def upload(key, io, checksum: nil)
- instrument :upload, key, checksum: checksum do
+ instrument :upload, key: key, checksum: checksum do
begin
- bucket.create_file(io, key, md5: checksum)
+ # The official GCS client library doesn't allow us to create a file with no Content-Type metadata.
+ # We need the file we create to have no Content-Type so we can control it via the response-content-type
+ # param in signed URLs. Workaround: let the GCS client create the file with an inferred
+ # Content-Type (usually "application/octet-stream") then clear it.
+ bucket.create_file(io, key, md5: checksum).update do |file|
+ file.content_type = nil
+ end
rescue Google::Cloud::InvalidArgumentError
raise ActiveStorage::IntegrityError
end
@@ -26,7 +31,7 @@ module ActiveStorage
# FIXME: Download in chunks when given a block.
def download(key)
- instrument :download, key do
+ instrument :download, key: key do
io = file_for(key).download
io.rewind
@@ -39,7 +44,7 @@ module ActiveStorage
end
def delete(key)
- instrument :delete, key do
+ instrument :delete, key: key do
begin
file_for(key).delete
rescue Google::Cloud::NotFoundError
@@ -48,8 +53,14 @@ module ActiveStorage
end
end
+ def delete_prefixed(prefix)
+ instrument :delete_prefixed, prefix: prefix do
+ bucket.files(prefix: prefix).all(&:delete)
+ end
+ end
+
def exist?(key)
- instrument :exist, key do |payload|
+ instrument :exist, key: key do |payload|
answer = file_for(key).exists?
payload[:exist] = answer
answer
@@ -57,7 +68,7 @@ module ActiveStorage
end
def url(key, expires_in:, filename:, content_type:, disposition:)
- instrument :url, key do |payload|
+ instrument :url, key: key do |payload|
generated_url = file_for(key).signed_url expires: expires_in, query: {
"response-content-disposition" => content_disposition_with(type: disposition, filename: filename),
"response-content-type" => content_type
@@ -70,7 +81,7 @@ module ActiveStorage
end
def url_for_direct_upload(key, expires_in:, content_type:, content_length:, checksum:)
- instrument :url, key do |payload|
+ instrument :url, key: key do |payload|
generated_url = bucket.signed_url key, method: "PUT", expires: expires_in,
content_type: content_type, content_md5: checksum
@@ -85,8 +96,18 @@ module ActiveStorage
end
private
+ attr_reader :config
+
def file_for(key)
bucket.file(key, skip_lookup: true)
end
+
+ def bucket
+ @bucket ||= client.bucket(config.fetch(:bucket))
+ end
+
+ def client
+ @client ||= Google::Cloud::Storage.new(config.except(:bucket))
+ end
end
end
diff --git a/activestorage/lib/active_storage/service/mirror_service.rb b/activestorage/lib/active_storage/service/mirror_service.rb
index 39e922f7ab..7eca8ce7f4 100644
--- a/activestorage/lib/active_storage/service/mirror_service.rb
+++ b/activestorage/lib/active_storage/service/mirror_service.rb
@@ -35,6 +35,11 @@ module ActiveStorage
perform_across_services :delete, key
end
+ # Delete files at keys starting with the +prefix+ on all services.
+ def delete_prefixed(prefix)
+ perform_across_services :delete_prefixed, prefix
+ end
+
private
def each_service(&block)
[ primary, *mirrors ].each(&block)
diff --git a/activestorage/lib/active_storage/service/s3_service.rb b/activestorage/lib/active_storage/service/s3_service.rb
index 3e93cdd072..c95672f338 100644
--- a/activestorage/lib/active_storage/service/s3_service.rb
+++ b/activestorage/lib/active_storage/service/s3_service.rb
@@ -17,7 +17,7 @@ module ActiveStorage
end
def upload(key, io, checksum: nil)
- instrument :upload, key, checksum: checksum do
+ instrument :upload, key: key, checksum: checksum do
begin
object_for(key).put(upload_options.merge(body: io, content_md5: checksum))
rescue Aws::S3::Errors::BadDigest
@@ -26,26 +26,32 @@ module ActiveStorage
end
end
- def download(key)
+ def download(key, &block)
if block_given?
- instrument :streaming_download, key do
+ instrument :streaming_download, key: key do
stream(key, &block)
end
else
- instrument :download, key do
+ instrument :download, key: key do
object_for(key).get.body.read.force_encoding(Encoding::BINARY)
end
end
end
def delete(key)
- instrument :delete, key do
+ instrument :delete, key: key do
object_for(key).delete
end
end
+ def delete_prefixed(prefix)
+ instrument :delete_prefixed, prefix: prefix do
+ bucket.objects(prefix: prefix).batch_delete!
+ end
+ end
+
def exist?(key)
- instrument :exist, key do |payload|
+ instrument :exist, key: key do |payload|
answer = object_for(key).exists?
payload[:exist] = answer
answer
@@ -53,7 +59,7 @@ module ActiveStorage
end
def url(key, expires_in:, filename:, disposition:, content_type:)
- instrument :url, key do |payload|
+ instrument :url, key: key do |payload|
generated_url = object_for(key).presigned_url :get, expires_in: expires_in.to_i,
response_content_disposition: content_disposition_with(type: disposition, filename: filename),
response_content_type: content_type
@@ -65,7 +71,7 @@ module ActiveStorage
end
def url_for_direct_upload(key, expires_in:, content_type:, content_length:, checksum:)
- instrument :url, key do |payload|
+ instrument :url, key: key do |payload|
generated_url = object_for(key).presigned_url :put, expires_in: expires_in.to_i,
content_type: content_type, content_length: content_length, content_md5: checksum
@@ -85,14 +91,14 @@ module ActiveStorage
end
# Reads the object for the given key in chunks, yielding each to the block.
- def stream(key, options = {}, &block)
+ def stream(key)
object = object_for(key)
chunk_size = 5.megabytes
offset = 0
while offset < object.content_length
- yield object.read(options.merge(range: "bytes=#{offset}-#{offset + chunk_size - 1}"))
+ yield object.get(range: "bytes=#{offset}-#{offset + chunk_size - 1}").body.read.force_encoding(Encoding::BINARY)
offset += chunk_size
end
end