activestorage 5.2.4.rc1 → 6.0.0.beta1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of activestorage might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +103 -66
- data/MIT-LICENSE +1 -1
- data/README.md +6 -5
- data/app/assets/javascripts/activestorage.js +4 -1
- data/app/controllers/active_storage/base_controller.rb +3 -5
- data/app/controllers/active_storage/blobs_controller.rb +1 -1
- data/app/controllers/active_storage/disk_controller.rb +4 -1
- data/app/controllers/active_storage/representations_controller.rb +1 -1
- data/app/controllers/concerns/active_storage/set_current.rb +15 -0
- data/app/javascript/activestorage/blob_record.js +6 -1
- data/app/jobs/active_storage/analyze_job.rb +4 -0
- data/app/jobs/active_storage/base_job.rb +0 -1
- data/app/jobs/active_storage/purge_job.rb +3 -0
- data/app/models/active_storage/attachment.rb +18 -9
- data/app/models/active_storage/blob.rb +63 -22
- data/app/models/active_storage/blob/representable.rb +5 -5
- data/app/models/active_storage/filename.rb +0 -6
- data/app/models/active_storage/preview.rb +3 -3
- data/app/models/active_storage/variant.rb +51 -52
- data/app/models/active_storage/variation.rb +23 -32
- data/config/routes.rb +13 -12
- data/db/update_migrate/20180723000244_add_foreign_key_constraint_to_active_storage_attachments_for_blob_id.rb +7 -0
- data/lib/active_storage.rb +13 -2
- data/lib/active_storage/analyzer.rb +9 -4
- data/lib/active_storage/analyzer/video_analyzer.rb +2 -4
- data/lib/active_storage/attached.rb +7 -22
- data/lib/active_storage/attached/changes.rb +16 -0
- data/lib/active_storage/attached/changes/create_many.rb +46 -0
- data/lib/active_storage/attached/changes/create_one.rb +68 -0
- data/lib/active_storage/attached/changes/create_one_of_many.rb +10 -0
- data/lib/active_storage/attached/changes/delete_many.rb +23 -0
- data/lib/active_storage/attached/changes/delete_one.rb +19 -0
- data/lib/active_storage/attached/many.rb +16 -10
- data/lib/active_storage/attached/model.rb +140 -0
- data/lib/active_storage/attached/one.rb +16 -19
- data/lib/active_storage/downloader.rb +44 -0
- data/lib/active_storage/downloading.rb +8 -0
- data/lib/active_storage/engine.rb +35 -6
- data/lib/active_storage/errors.rb +22 -3
- data/lib/active_storage/gem_version.rb +4 -4
- data/lib/active_storage/previewer.rb +21 -11
- data/lib/active_storage/previewer/poppler_pdf_previewer.rb +1 -1
- data/lib/active_storage/previewer/video_previewer.rb +2 -3
- data/lib/active_storage/reflection.rb +64 -0
- data/lib/active_storage/service.rb +5 -6
- data/lib/active_storage/service/azure_storage_service.rb +28 -12
- data/lib/active_storage/service/configurator.rb +3 -1
- data/lib/active_storage/service/disk_service.rb +20 -16
- data/lib/active_storage/service/gcs_service.rb +48 -46
- data/lib/active_storage/service/mirror_service.rb +1 -1
- data/lib/active_storage/service/s3_service.rb +9 -5
- data/lib/active_storage/transformers/image_processing_transformer.rb +39 -0
- data/lib/active_storage/transformers/mini_magick_transformer.rb +38 -0
- data/lib/active_storage/transformers/transformer.rb +42 -0
- data/lib/tasks/activestorage.rake +7 -0
- metadata +24 -12
- data/app/models/active_storage/filename/parameters.rb +0 -36
- data/lib/active_storage/attached/macros.rb +0 -110
@@ -10,26 +10,28 @@ module ActiveStorage
|
|
10
10
|
# You don't have to call this method to access the attachment's methods as
|
11
11
|
# they are all available at the model level.
|
12
12
|
def attachment
|
13
|
-
record.public_send("#{name}_attachment")
|
13
|
+
change.present? ? change.attachment : record.public_send("#{name}_attachment")
|
14
14
|
end
|
15
15
|
|
16
|
-
|
16
|
+
def blank?
|
17
|
+
!attached?
|
18
|
+
end
|
19
|
+
|
20
|
+
# Attaches an +attachable+ to the record.
|
21
|
+
#
|
22
|
+
# If the record is persisted and unchanged, the attachment is saved to
|
23
|
+
# the database immediately. Otherwise, it'll be saved to the DB when the
|
24
|
+
# record is next saved.
|
17
25
|
#
|
18
26
|
# person.avatar.attach(params[:avatar]) # ActionDispatch::Http::UploadedFile object
|
19
27
|
# person.avatar.attach(params[:signed_blob_id]) # Signed reference to blob from direct upload
|
20
28
|
# person.avatar.attach(io: File.open("/path/to/face.jpg"), filename: "face.jpg", content_type: "image/jpg")
|
21
29
|
# person.avatar.attach(avatar_blob) # ActiveStorage::Blob object
|
22
30
|
def attach(attachable)
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
transaction do
|
28
|
-
detach
|
29
|
-
write_attachment build_attachment(blob: blob)
|
30
|
-
end
|
31
|
-
|
32
|
-
blob_was.purge_later if blob_was && dependent == :purge_later
|
31
|
+
if record.persisted? && !record.changed?
|
32
|
+
record.update(name => attachable)
|
33
|
+
else
|
34
|
+
record.public_send("#{name}=", attachable)
|
33
35
|
end
|
34
36
|
end
|
35
37
|
|
@@ -47,7 +49,7 @@ module ActiveStorage
|
|
47
49
|
# Deletes the attachment without purging it, leaving its blob in place.
|
48
50
|
def detach
|
49
51
|
if attached?
|
50
|
-
attachment.
|
52
|
+
attachment.delete
|
51
53
|
write_attachment nil
|
52
54
|
end
|
53
55
|
end
|
@@ -65,16 +67,11 @@ module ActiveStorage
|
|
65
67
|
def purge_later
|
66
68
|
if attached?
|
67
69
|
attachment.purge_later
|
70
|
+
write_attachment nil
|
68
71
|
end
|
69
72
|
end
|
70
73
|
|
71
74
|
private
|
72
|
-
delegate :transaction, to: :record
|
73
|
-
|
74
|
-
def build_attachment(blob:)
|
75
|
-
ActiveStorage::Attachment.new(record: record, name: name, blob: blob)
|
76
|
-
end
|
77
|
-
|
78
75
|
def write_attachment(attachment)
|
79
76
|
record.public_send("#{name}_attachment=", attachment)
|
80
77
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveStorage
|
4
|
+
class Downloader #:nodoc:
|
5
|
+
def initialize(blob, tempdir: nil)
|
6
|
+
@blob = blob
|
7
|
+
@tempdir = tempdir
|
8
|
+
end
|
9
|
+
|
10
|
+
def download_blob_to_tempfile
|
11
|
+
open_tempfile do |file|
|
12
|
+
download_blob_to file
|
13
|
+
verify_integrity_of file
|
14
|
+
yield file
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
attr_reader :blob, :tempdir
|
20
|
+
|
21
|
+
def open_tempfile
|
22
|
+
file = Tempfile.open([ "ActiveStorage-#{blob.id}-", blob.filename.extension_with_delimiter ], tempdir)
|
23
|
+
|
24
|
+
begin
|
25
|
+
yield file
|
26
|
+
ensure
|
27
|
+
file.close!
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def download_blob_to(file)
|
32
|
+
file.binmode
|
33
|
+
blob.download { |chunk| file.write(chunk) }
|
34
|
+
file.flush
|
35
|
+
file.rewind
|
36
|
+
end
|
37
|
+
|
38
|
+
def verify_integrity_of(file)
|
39
|
+
unless Digest::MD5.file(file).base64digest == blob.checksum
|
40
|
+
raise ActiveStorage::IntegrityError
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -1,9 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "tmpdir"
|
4
|
+
require "active_support/core_ext/string/filters"
|
4
5
|
|
5
6
|
module ActiveStorage
|
6
7
|
module Downloading
|
8
|
+
def self.included(klass)
|
9
|
+
ActiveSupport::Deprecation.warn <<~MESSAGE.squish, caller_locations(2)
|
10
|
+
ActiveStorage::Downloading is deprecated and will be removed in Active Storage 6.1.
|
11
|
+
Use ActiveStorage::Blob#open instead.
|
12
|
+
MESSAGE
|
13
|
+
end
|
14
|
+
|
7
15
|
private
|
8
16
|
# Opens a new tempfile in #tempdir and copies blob data into it. Yields the tempfile.
|
9
17
|
def download_blob_to_tempfile #:doc:
|
@@ -10,6 +10,8 @@ require "active_storage/previewer/video_previewer"
|
|
10
10
|
require "active_storage/analyzer/image_analyzer"
|
11
11
|
require "active_storage/analyzer/video_analyzer"
|
12
12
|
|
13
|
+
require "active_storage/reflection"
|
14
|
+
|
13
15
|
module ActiveStorage
|
14
16
|
class Engine < Rails::Engine # :nodoc:
|
15
17
|
isolate_namespace ActiveStorage
|
@@ -18,12 +20,15 @@ module ActiveStorage
|
|
18
20
|
config.active_storage.previewers = [ ActiveStorage::Previewer::PopplerPDFPreviewer, ActiveStorage::Previewer::MuPDFPreviewer, ActiveStorage::Previewer::VideoPreviewer ]
|
19
21
|
config.active_storage.analyzers = [ ActiveStorage::Analyzer::ImageAnalyzer, ActiveStorage::Analyzer::VideoAnalyzer ]
|
20
22
|
config.active_storage.paths = ActiveSupport::OrderedOptions.new
|
23
|
+
config.active_storage.queues = ActiveSupport::OrderedOptions.new
|
21
24
|
|
22
25
|
config.active_storage.variable_content_types = %w(
|
23
26
|
image/png
|
24
27
|
image/gif
|
25
28
|
image/jpg
|
26
29
|
image/jpeg
|
30
|
+
image/pjpeg
|
31
|
+
image/tiff
|
27
32
|
image/vnd.adobe.photoshop
|
28
33
|
image/vnd.microsoft.icon
|
29
34
|
)
|
@@ -46,6 +51,7 @@ module ActiveStorage
|
|
46
51
|
image/gif
|
47
52
|
image/jpg
|
48
53
|
image/jpeg
|
54
|
+
image/tiff
|
49
55
|
image/vnd.adobe.photoshop
|
50
56
|
image/vnd.microsoft.icon
|
51
57
|
application/pdf
|
@@ -55,14 +61,16 @@ module ActiveStorage
|
|
55
61
|
|
56
62
|
initializer "active_storage.configs" do
|
57
63
|
config.after_initialize do |app|
|
58
|
-
ActiveStorage.logger
|
59
|
-
ActiveStorage.
|
60
|
-
ActiveStorage.previewers
|
61
|
-
ActiveStorage.analyzers
|
62
|
-
ActiveStorage.paths
|
64
|
+
ActiveStorage.logger = app.config.active_storage.logger || Rails.logger
|
65
|
+
ActiveStorage.variant_processor = app.config.active_storage.variant_processor || :mini_magick
|
66
|
+
ActiveStorage.previewers = app.config.active_storage.previewers || []
|
67
|
+
ActiveStorage.analyzers = app.config.active_storage.analyzers || []
|
68
|
+
ActiveStorage.paths = app.config.active_storage.paths || {}
|
69
|
+
ActiveStorage.routes_prefix = app.config.active_storage.routes_prefix || "/rails/active_storage"
|
63
70
|
|
64
71
|
ActiveStorage.variable_content_types = app.config.active_storage.variable_content_types || []
|
65
72
|
ActiveStorage.content_types_to_serve_as_binary = app.config.active_storage.content_types_to_serve_as_binary || []
|
73
|
+
ActiveStorage.service_urls_expire_in = app.config.active_storage.service_urls_expire_in || 5.minutes
|
66
74
|
ActiveStorage.content_types_allowed_inline = app.config.active_storage.content_types_allowed_inline || []
|
67
75
|
ActiveStorage.binary_content_type = app.config.active_storage.binary_content_type || "application/octet-stream"
|
68
76
|
end
|
@@ -72,7 +80,7 @@ module ActiveStorage
|
|
72
80
|
require "active_storage/attached"
|
73
81
|
|
74
82
|
ActiveSupport.on_load(:active_record) do
|
75
|
-
|
83
|
+
include ActiveStorage::Attached::Model
|
76
84
|
end
|
77
85
|
end
|
78
86
|
|
@@ -108,5 +116,26 @@ module ActiveStorage
|
|
108
116
|
end
|
109
117
|
end
|
110
118
|
end
|
119
|
+
|
120
|
+
initializer "active_storage.queues" do
|
121
|
+
config.after_initialize do |app|
|
122
|
+
if queue = app.config.active_storage.queue
|
123
|
+
ActiveSupport::Deprecation.warn \
|
124
|
+
"config.active_storage.queue is deprecated and will be removed in Rails 6.1. " \
|
125
|
+
"Set config.active_storage.queues.purge and config.active_storage.queues.analysis instead."
|
126
|
+
|
127
|
+
ActiveStorage.queues = { purge: queue, analysis: queue }
|
128
|
+
else
|
129
|
+
ActiveStorage.queues = app.config.active_storage.queues || {}
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
initializer "active_storage.reflection" do
|
135
|
+
ActiveSupport.on_load(:active_record) do
|
136
|
+
include Reflection::ActiveRecordExtensions
|
137
|
+
ActiveRecord::Reflection.singleton_class.prepend(Reflection::ReflectionExtension)
|
138
|
+
end
|
139
|
+
end
|
111
140
|
end
|
112
141
|
end
|
@@ -1,7 +1,26 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveStorage
|
4
|
-
class
|
5
|
-
class
|
6
|
-
|
4
|
+
# Generic base class for all Active Storage exceptions.
|
5
|
+
class Error < StandardError; end
|
6
|
+
|
7
|
+
# Raised when ActiveStorage::Blob#variant is called on a blob that isn't variable.
|
8
|
+
# Use ActiveStorage::Blob#variable? to determine whether a blob is variable.
|
9
|
+
class InvariableError < Error; end
|
10
|
+
|
11
|
+
# Raised when ActiveStorage::Blob#preview is called on a blob that isn't previewable.
|
12
|
+
# Use ActiveStorage::Blob#previewable? to determine whether a blob is previewable.
|
13
|
+
class UnpreviewableError < Error; end
|
14
|
+
|
15
|
+
# Raised when ActiveStorage::Blob#representation is called on a blob that isn't representable.
|
16
|
+
# Use ActiveStorage::Blob#representable? to determine whether a blob is representable.
|
17
|
+
class UnrepresentableError < Error; end
|
18
|
+
|
19
|
+
# Raised when uploaded or downloaded data does not match a precomputed checksum.
|
20
|
+
# Indicates that a network error or a software bug caused data corruption.
|
21
|
+
class IntegrityError < Error; end
|
22
|
+
|
23
|
+
# Raised when ActiveStorage::Blob#download is called on a blob where the
|
24
|
+
# backing file is no longer present in its service.
|
25
|
+
class FileNotFoundError < Error; end
|
7
26
|
end
|
@@ -1,14 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "active_storage/downloading"
|
4
|
-
|
5
3
|
module ActiveStorage
|
6
4
|
# This is an abstract base class for previewers, which generate images from blobs. See
|
7
5
|
# ActiveStorage::Previewer::MuPDFPreviewer and ActiveStorage::Previewer::VideoPreviewer for
|
8
6
|
# examples of concrete subclasses.
|
9
7
|
class Previewer
|
10
|
-
include Downloading
|
11
|
-
|
12
8
|
attr_reader :blob
|
13
9
|
|
14
10
|
# Implement this method in a concrete subclass. Have it return true when given a blob from which
|
@@ -28,9 +24,14 @@ module ActiveStorage
|
|
28
24
|
end
|
29
25
|
|
30
26
|
private
|
27
|
+
# Downloads the blob to a tempfile on disk. Yields the tempfile.
|
28
|
+
def download_blob_to_tempfile(&block) #:doc:
|
29
|
+
blob.open tempdir: tempdir, &block
|
30
|
+
end
|
31
|
+
|
31
32
|
# Executes a system command, capturing its binary output in a tempfile. Yields the tempfile.
|
32
33
|
#
|
33
|
-
# Use this method to shell out to a system library (e.g.
|
34
|
+
# Use this method to shell out to a system library (e.g. muPDF or FFmpeg) for preview image
|
34
35
|
# generation. The resulting tempfile can be used as the +:io+ value in an attachable Hash:
|
35
36
|
#
|
36
37
|
# def preview
|
@@ -41,18 +42,19 @@ module ActiveStorage
|
|
41
42
|
# end
|
42
43
|
# end
|
43
44
|
#
|
44
|
-
# The output tempfile is opened in the directory returned by
|
45
|
+
# The output tempfile is opened in the directory returned by #tempdir.
|
45
46
|
def draw(*argv) #:doc:
|
46
|
-
|
47
|
-
|
47
|
+
open_tempfile do |file|
|
48
|
+
instrument :preview, key: blob.key do
|
48
49
|
capture(*argv, to: file)
|
49
|
-
yield file
|
50
50
|
end
|
51
|
+
|
52
|
+
yield file
|
51
53
|
end
|
52
54
|
end
|
53
55
|
|
54
|
-
def
|
55
|
-
tempfile = Tempfile.open("ActiveStorage", tempdir)
|
56
|
+
def open_tempfile
|
57
|
+
tempfile = Tempfile.open("ActiveStorage-", tempdir)
|
56
58
|
|
57
59
|
begin
|
58
60
|
yield tempfile
|
@@ -61,6 +63,10 @@ module ActiveStorage
|
|
61
63
|
end
|
62
64
|
end
|
63
65
|
|
66
|
+
def instrument(operation, payload = {}, &block)
|
67
|
+
ActiveSupport::Notifications.instrument "#{operation}.active_storage", payload, &block
|
68
|
+
end
|
69
|
+
|
64
70
|
def capture(*argv, to:)
|
65
71
|
to.binmode
|
66
72
|
IO.popen(argv, err: File::NULL) { |out| IO.copy_stream(out, to) }
|
@@ -70,5 +76,9 @@ module ActiveStorage
|
|
70
76
|
def logger #:doc:
|
71
77
|
ActiveStorage.logger
|
72
78
|
end
|
79
|
+
|
80
|
+
def tempdir #:doc:
|
81
|
+
Dir.tmpdir
|
82
|
+
end
|
73
83
|
end
|
74
84
|
end
|
@@ -12,7 +12,7 @@ module ActiveStorage
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def pdftoppm_exists?
|
15
|
-
return @pdftoppm_exists
|
15
|
+
return @pdftoppm_exists if defined?(@pdftoppm_exists)
|
16
16
|
|
17
17
|
@pdftoppm_exists = system(pdftoppm_path, "-v", out: File::NULL, err: File::NULL)
|
18
18
|
end
|
@@ -9,15 +9,14 @@ module ActiveStorage
|
|
9
9
|
def preview
|
10
10
|
download_blob_to_tempfile do |input|
|
11
11
|
draw_relevant_frame_from input do |output|
|
12
|
-
yield io: output, filename: "#{blob.filename.base}.
|
12
|
+
yield io: output, filename: "#{blob.filename.base}.jpg", content_type: "image/jpeg"
|
13
13
|
end
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
17
|
private
|
18
18
|
def draw_relevant_frame_from(file, &block)
|
19
|
-
draw ffmpeg_path, "-i", file.path, "-y", "-
|
20
|
-
"-vf", "thumbnail", "-vframes", "1", "-f", "image2", "-", &block
|
19
|
+
draw ffmpeg_path, "-i", file.path, "-y", "-vframes", "1", "-f", "image2", "-", &block
|
21
20
|
end
|
22
21
|
|
23
22
|
def ffmpeg_path
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveStorage
|
4
|
+
module Reflection
|
5
|
+
# Holds all the metadata about a has_one_attached attachment as it was
|
6
|
+
# specified in the Active Record class.
|
7
|
+
class HasOneAttachedReflection < ActiveRecord::Reflection::MacroReflection #:nodoc:
|
8
|
+
def macro
|
9
|
+
:has_one_attached
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# Holds all the metadata about a has_many_attached attachment as it was
|
14
|
+
# specified in the Active Record class.
|
15
|
+
class HasManyAttachedReflection < ActiveRecord::Reflection::MacroReflection #:nodoc:
|
16
|
+
def macro
|
17
|
+
:has_many_attached
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
module ReflectionExtension # :nodoc:
|
22
|
+
def add_attachment_reflection(model, name, reflection)
|
23
|
+
model.attachment_reflections = model.attachment_reflections.merge(name.to_s => reflection)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
def reflection_class_for(macro)
|
28
|
+
case macro
|
29
|
+
when :has_one_attached
|
30
|
+
HasOneAttachedReflection
|
31
|
+
when :has_many_attached
|
32
|
+
HasManyAttachedReflection
|
33
|
+
else
|
34
|
+
super
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
module ActiveRecordExtensions
|
40
|
+
extend ActiveSupport::Concern
|
41
|
+
|
42
|
+
included do
|
43
|
+
class_attribute :attachment_reflections, instance_writer: false, default: {}
|
44
|
+
end
|
45
|
+
|
46
|
+
module ClassMethods
|
47
|
+
# Returns an array of reflection objects for all the attachments in the
|
48
|
+
# class.
|
49
|
+
def reflect_on_all_attachments
|
50
|
+
attachment_reflections.values
|
51
|
+
end
|
52
|
+
|
53
|
+
# Returns the reflection object for the named +attachment+.
|
54
|
+
#
|
55
|
+
# User.reflect_on_attachment(:avatar)
|
56
|
+
# # => the avatar reflection
|
57
|
+
#
|
58
|
+
def reflect_on_attachment(attachment)
|
59
|
+
attachment_reflections[attachment.to_s]
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -1,10 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "active_storage/log_subscriber"
|
4
|
+
require "action_dispatch"
|
5
|
+
require "action_dispatch/http/content_disposition"
|
4
6
|
|
5
7
|
module ActiveStorage
|
6
|
-
class IntegrityError < StandardError; end
|
7
|
-
|
8
8
|
# Abstract class serving as an interface for concrete services.
|
9
9
|
#
|
10
10
|
# The available services are:
|
@@ -41,8 +41,6 @@ module ActiveStorage
|
|
41
41
|
extend ActiveSupport::Autoload
|
42
42
|
autoload :Configurator
|
43
43
|
|
44
|
-
class_attribute :url_expires_in, default: 5.minutes
|
45
|
-
|
46
44
|
class << self
|
47
45
|
# Configure an Active Storage service by name from a set of configurations,
|
48
46
|
# typically loaded from a YAML file. The Active Storage engine uses this
|
@@ -100,7 +98,7 @@ module ActiveStorage
|
|
100
98
|
end
|
101
99
|
|
102
100
|
# Returns a signed, temporary URL for the file at the +key+. The URL will be valid for the amount
|
103
|
-
# of seconds specified in +expires_in+. You
|
101
|
+
# of seconds specified in +expires_in+. You must also provide the +disposition+ (+:inline+ or +:attachment+),
|
104
102
|
# +filename+, and +content_type+ that you wish the file to be served with on request.
|
105
103
|
def url(key, expires_in:, disposition:, filename:, content_type:)
|
106
104
|
raise NotImplementedError
|
@@ -132,7 +130,8 @@ module ActiveStorage
|
|
132
130
|
end
|
133
131
|
|
134
132
|
def content_disposition_with(type: "inline", filename:)
|
135
|
-
(type.to_s.presence_in(%w( attachment inline )) || "inline")
|
133
|
+
disposition = (type.to_s.presence_in(%w( attachment inline )) || "inline")
|
134
|
+
ActionDispatch::Http::ContentDisposition.format(disposition: disposition, filename: filename.sanitized)
|
136
135
|
end
|
137
136
|
end
|
138
137
|
end
|