activestorage 5.2.6.3 → 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 +102 -134
- 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/representable.rb +5 -5
- data/app/models/active_storage/blob.rb +63 -22
- 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 -384
- 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/analyzer/video_analyzer.rb +2 -4
- data/lib/active_storage/analyzer.rb +9 -4
- 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/changes.rb +16 -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/attached.rb +7 -22
- data/lib/active_storage/downloader.rb +44 -0
- data/lib/active_storage/downloading.rb +8 -0
- data/lib/active_storage/engine.rb +36 -23
- data/lib/active_storage/errors.rb +22 -3
- data/lib/active_storage/gem_version.rb +4 -4
- data/lib/active_storage/previewer/poppler_pdf_previewer.rb +3 -3
- data/lib/active_storage/previewer/video_previewer.rb +2 -3
- data/lib/active_storage/previewer.rb +21 -11
- data/lib/active_storage/reflection.rb +64 -0
- data/lib/active_storage/service/azure_storage_service.rb +30 -14
- 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 +10 -9
- data/lib/active_storage/service.rb +5 -6
- 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/active_storage.rb +13 -4
- data/lib/tasks/activestorage.rake +7 -0
- metadata +31 -19
- data/app/models/active_storage/filename/parameters.rb +0 -36
- data/lib/active_storage/attached/macros.rb +0 -110
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveStorage
|
4
|
+
class Attached::Changes::DeleteOne #:nodoc:
|
5
|
+
attr_reader :name, :record
|
6
|
+
|
7
|
+
def initialize(name, record)
|
8
|
+
@name, @record = name, record
|
9
|
+
end
|
10
|
+
|
11
|
+
def attachment
|
12
|
+
nil
|
13
|
+
end
|
14
|
+
|
15
|
+
def save
|
16
|
+
record.public_send("#{name}_attachment=", nil)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveStorage
|
4
|
+
module Attached::Changes #:nodoc:
|
5
|
+
extend ActiveSupport::Autoload
|
6
|
+
|
7
|
+
eager_autoload do
|
8
|
+
autoload :CreateOne
|
9
|
+
autoload :CreateMany
|
10
|
+
autoload :CreateOneOfMany
|
11
|
+
|
12
|
+
autoload :DeleteOne
|
13
|
+
autoload :DeleteMany
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -9,22 +9,29 @@ module ActiveStorage
|
|
9
9
|
#
|
10
10
|
# All methods called on this proxy object that aren't listed here will automatically be delegated to +attachments+.
|
11
11
|
def attachments
|
12
|
-
record.public_send("#{name}_attachments")
|
12
|
+
change.present? ? change.attachments : record.public_send("#{name}_attachments")
|
13
13
|
end
|
14
14
|
|
15
|
-
#
|
15
|
+
# Returns all attached blobs.
|
16
|
+
def blobs
|
17
|
+
change.present? ? change.blobs : record.public_send("#{name}_blobs")
|
18
|
+
end
|
19
|
+
|
20
|
+
# Attaches one or more +attachables+ to the record.
|
21
|
+
#
|
22
|
+
# If the record is persisted and unchanged, the attachments are saved to
|
23
|
+
# the database immediately. Otherwise, they'll be saved to the DB when the
|
24
|
+
# record is next saved.
|
16
25
|
#
|
17
26
|
# document.images.attach(params[:images]) # Array of ActionDispatch::Http::UploadedFile objects
|
18
27
|
# document.images.attach(params[:signed_blob_id]) # Signed reference to blob from direct upload
|
19
28
|
# document.images.attach(io: File.open("/path/to/racecar.jpg"), filename: "racecar.jpg", content_type: "image/jpg")
|
20
29
|
# document.images.attach([ first_blob, second_blob ])
|
21
30
|
def attach(*attachables)
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
attachments.create!(record: record, blob: create_blob_from(attachable))
|
27
|
-
end
|
31
|
+
if record.persisted? && !record.changed?
|
32
|
+
record.update(name => blobs + attachables.flatten)
|
33
|
+
else
|
34
|
+
record.public_send("#{name}=", blobs + attachables.flatten)
|
28
35
|
end
|
29
36
|
end
|
30
37
|
|
@@ -41,7 +48,7 @@ module ActiveStorage
|
|
41
48
|
|
42
49
|
# Deletes associated attachments without purging them, leaving their respective blobs in place.
|
43
50
|
def detach
|
44
|
-
attachments.
|
51
|
+
attachments.delete_all if attached?
|
45
52
|
end
|
46
53
|
|
47
54
|
##
|
@@ -50,7 +57,6 @@ module ActiveStorage
|
|
50
57
|
# Directly purges each associated attachment (i.e. destroys the blobs and
|
51
58
|
# attachments and deletes the files on the service).
|
52
59
|
|
53
|
-
|
54
60
|
##
|
55
61
|
# :method: purge_later
|
56
62
|
#
|
@@ -0,0 +1,140 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveStorage
|
4
|
+
# Provides the class-level DSL for declaring an Active Record model's attachments.
|
5
|
+
module Attached::Model
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
class_methods do
|
9
|
+
# Specifies the relation between a single attachment and the model.
|
10
|
+
#
|
11
|
+
# class User < ActiveRecord::Base
|
12
|
+
# has_one_attached :avatar
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# There is no column defined on the model side, Active Storage takes
|
16
|
+
# care of the mapping between your records and the attachment.
|
17
|
+
#
|
18
|
+
# To avoid N+1 queries, you can include the attached blobs in your query like so:
|
19
|
+
#
|
20
|
+
# User.with_attached_avatar
|
21
|
+
#
|
22
|
+
# Under the covers, this relationship is implemented as a +has_one+ association to a
|
23
|
+
# ActiveStorage::Attachment record and a +has_one-through+ association to a
|
24
|
+
# ActiveStorage::Blob record. These associations are available as +avatar_attachment+
|
25
|
+
# and +avatar_blob+. But you shouldn't need to work with these associations directly in
|
26
|
+
# most circumstances.
|
27
|
+
#
|
28
|
+
# The system has been designed to having you go through the ActiveStorage::Attached::One
|
29
|
+
# proxy that provides the dynamic proxy to the associations and factory methods, like +attach+.
|
30
|
+
#
|
31
|
+
# If the +:dependent+ option isn't set, the attachment will be purged
|
32
|
+
# (i.e. destroyed) whenever the record is destroyed.
|
33
|
+
def has_one_attached(name, dependent: :purge_later)
|
34
|
+
generated_association_methods.class_eval <<-CODE, __FILE__, __LINE__ + 1
|
35
|
+
def #{name}
|
36
|
+
@active_storage_attached_#{name} ||= ActiveStorage::Attached::One.new("#{name}", self)
|
37
|
+
end
|
38
|
+
|
39
|
+
def #{name}=(attachable)
|
40
|
+
attachment_changes["#{name}"] =
|
41
|
+
if attachable.nil?
|
42
|
+
ActiveStorage::Attached::Changes::DeleteOne.new("#{name}", self)
|
43
|
+
else
|
44
|
+
ActiveStorage::Attached::Changes::CreateOne.new("#{name}", self, attachable)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
CODE
|
48
|
+
|
49
|
+
has_one :"#{name}_attachment", -> { where(name: name) }, class_name: "ActiveStorage::Attachment", as: :record, inverse_of: :record, dependent: :destroy
|
50
|
+
has_one :"#{name}_blob", through: :"#{name}_attachment", class_name: "ActiveStorage::Blob", source: :blob
|
51
|
+
|
52
|
+
scope :"with_attached_#{name}", -> { includes("#{name}_attachment": :blob) }
|
53
|
+
|
54
|
+
after_save { attachment_changes[name.to_s]&.save }
|
55
|
+
|
56
|
+
after_commit(on: %i[ create update ]) { attachment_changes.delete(name.to_s).try(:upload) }
|
57
|
+
|
58
|
+
ActiveRecord::Reflection.add_attachment_reflection(
|
59
|
+
self,
|
60
|
+
name,
|
61
|
+
ActiveRecord::Reflection.create(:has_one_attached, name, nil, { dependent: dependent }, self)
|
62
|
+
)
|
63
|
+
end
|
64
|
+
|
65
|
+
# Specifies the relation between multiple attachments and the model.
|
66
|
+
#
|
67
|
+
# class Gallery < ActiveRecord::Base
|
68
|
+
# has_many_attached :photos
|
69
|
+
# end
|
70
|
+
#
|
71
|
+
# There are no columns defined on the model side, Active Storage takes
|
72
|
+
# care of the mapping between your records and the attachments.
|
73
|
+
#
|
74
|
+
# To avoid N+1 queries, you can include the attached blobs in your query like so:
|
75
|
+
#
|
76
|
+
# Gallery.where(user: Current.user).with_attached_photos
|
77
|
+
#
|
78
|
+
# Under the covers, this relationship is implemented as a +has_many+ association to a
|
79
|
+
# ActiveStorage::Attachment record and a +has_many-through+ association to a
|
80
|
+
# ActiveStorage::Blob record. These associations are available as +photos_attachments+
|
81
|
+
# and +photos_blobs+. But you shouldn't need to work with these associations directly in
|
82
|
+
# most circumstances.
|
83
|
+
#
|
84
|
+
# The system has been designed to having you go through the ActiveStorage::Attached::Many
|
85
|
+
# proxy that provides the dynamic proxy to the associations and factory methods, like +#attach+.
|
86
|
+
#
|
87
|
+
# If the +:dependent+ option isn't set, all the attachments will be purged
|
88
|
+
# (i.e. destroyed) whenever the record is destroyed.
|
89
|
+
def has_many_attached(name, dependent: :purge_later)
|
90
|
+
generated_association_methods.class_eval <<-CODE, __FILE__, __LINE__ + 1
|
91
|
+
def #{name}
|
92
|
+
@active_storage_attached_#{name} ||= ActiveStorage::Attached::Many.new("#{name}", self)
|
93
|
+
end
|
94
|
+
|
95
|
+
def #{name}=(attachables)
|
96
|
+
attachment_changes["#{name}"] =
|
97
|
+
if attachables.nil? || Array(attachables).none?
|
98
|
+
ActiveStorage::Attached::Changes::DeleteMany.new("#{name}", self)
|
99
|
+
else
|
100
|
+
ActiveStorage::Attached::Changes::CreateMany.new("#{name}", self, attachables)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
CODE
|
104
|
+
|
105
|
+
has_many :"#{name}_attachments", -> { where(name: name) }, as: :record, class_name: "ActiveStorage::Attachment", inverse_of: :record, dependent: :destroy do
|
106
|
+
def purge
|
107
|
+
each(&:purge)
|
108
|
+
reset
|
109
|
+
end
|
110
|
+
|
111
|
+
def purge_later
|
112
|
+
each(&:purge_later)
|
113
|
+
reset
|
114
|
+
end
|
115
|
+
end
|
116
|
+
has_many :"#{name}_blobs", through: :"#{name}_attachments", class_name: "ActiveStorage::Blob", source: :blob
|
117
|
+
|
118
|
+
scope :"with_attached_#{name}", -> { includes("#{name}_attachments": :blob) }
|
119
|
+
|
120
|
+
after_save { attachment_changes[name.to_s]&.save }
|
121
|
+
|
122
|
+
after_commit(on: %i[ create update ]) { attachment_changes.delete(name.to_s).try(:upload) }
|
123
|
+
|
124
|
+
ActiveRecord::Reflection.add_attachment_reflection(
|
125
|
+
self,
|
126
|
+
name,
|
127
|
+
ActiveRecord::Reflection.create(:has_many_attached, name, nil, { dependent: dependent }, self)
|
128
|
+
)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def attachment_changes #:nodoc:
|
133
|
+
@attachment_changes ||= {}
|
134
|
+
end
|
135
|
+
|
136
|
+
def reload(*) #:nodoc:
|
137
|
+
super.tap { @attachment_changes = nil }
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
@@ -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
|
@@ -1,40 +1,25 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "action_dispatch"
|
4
|
-
require "action_dispatch/http/upload"
|
5
3
|
require "active_support/core_ext/module/delegation"
|
6
4
|
|
7
5
|
module ActiveStorage
|
8
6
|
# Abstract base class for the concrete ActiveStorage::Attached::One and ActiveStorage::Attached::Many
|
9
7
|
# classes that both provide proxy access to the blob association for a record.
|
10
8
|
class Attached
|
11
|
-
attr_reader :name, :record
|
9
|
+
attr_reader :name, :record
|
12
10
|
|
13
|
-
def initialize(name, record
|
14
|
-
@name, @record
|
11
|
+
def initialize(name, record)
|
12
|
+
@name, @record = name, record
|
15
13
|
end
|
16
14
|
|
17
15
|
private
|
18
|
-
def
|
19
|
-
|
20
|
-
when ActiveStorage::Blob
|
21
|
-
attachable
|
22
|
-
when ActionDispatch::Http::UploadedFile, Rack::Test::UploadedFile
|
23
|
-
ActiveStorage::Blob.create_after_upload! \
|
24
|
-
io: attachable.open,
|
25
|
-
filename: attachable.original_filename,
|
26
|
-
content_type: attachable.content_type
|
27
|
-
when Hash
|
28
|
-
ActiveStorage::Blob.create_after_upload!(attachable)
|
29
|
-
when String
|
30
|
-
ActiveStorage::Blob.find_signed(attachable)
|
31
|
-
else
|
32
|
-
nil
|
33
|
-
end
|
16
|
+
def change
|
17
|
+
record.attachment_changes[name]
|
34
18
|
end
|
35
19
|
end
|
36
20
|
end
|
37
21
|
|
22
|
+
require "active_storage/attached/model"
|
38
23
|
require "active_storage/attached/one"
|
39
24
|
require "active_storage/attached/many"
|
40
|
-
require "active_storage/attached/
|
25
|
+
require "active_storage/attached/changes"
|
@@ -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,39 +51,26 @@ 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
|
52
58
|
)
|
53
59
|
|
54
|
-
default_unsupported_image_processing_arguments = %w(
|
55
|
-
-debug
|
56
|
-
-display
|
57
|
-
-distribute-cache
|
58
|
-
-help
|
59
|
-
-path
|
60
|
-
-print
|
61
|
-
-set
|
62
|
-
-verbose
|
63
|
-
-version
|
64
|
-
-write
|
65
|
-
-write-mask
|
66
|
-
)
|
67
|
-
|
68
60
|
config.eager_load_namespaces << ActiveStorage
|
69
61
|
|
70
62
|
initializer "active_storage.configs" do
|
71
63
|
config.after_initialize do |app|
|
72
|
-
ActiveStorage.logger
|
73
|
-
ActiveStorage.
|
74
|
-
ActiveStorage.previewers
|
75
|
-
ActiveStorage.analyzers
|
76
|
-
ActiveStorage.paths
|
77
|
-
|
78
|
-
|
79
|
-
ActiveStorage.unsupported_image_processing_arguments = app.config.active_storage.unsupported_image_processing_arguments || default_unsupported_image_processing_arguments
|
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"
|
70
|
+
|
80
71
|
ActiveStorage.variable_content_types = app.config.active_storage.variable_content_types || []
|
81
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
|
82
74
|
ActiveStorage.content_types_allowed_inline = app.config.active_storage.content_types_allowed_inline || []
|
83
75
|
ActiveStorage.binary_content_type = app.config.active_storage.binary_content_type || "application/octet-stream"
|
84
76
|
end
|
@@ -88,7 +80,7 @@ module ActiveStorage
|
|
88
80
|
require "active_storage/attached"
|
89
81
|
|
90
82
|
ActiveSupport.on_load(:active_record) do
|
91
|
-
|
83
|
+
include ActiveStorage::Attached::Model
|
92
84
|
end
|
93
85
|
end
|
94
86
|
|
@@ -124,5 +116,26 @@ module ActiveStorage
|
|
124
116
|
end
|
125
117
|
end
|
126
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
|
127
140
|
end
|
128
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
|
@@ -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
|
@@ -28,8 +28,8 @@ module ActiveStorage
|
|
28
28
|
|
29
29
|
private
|
30
30
|
def draw_first_page_from(file, &block)
|
31
|
-
# use 72 dpi to match thumbnail
|
32
|
-
draw self.class.pdftoppm_path, "-singlefile", "-
|
31
|
+
# use 72 dpi to match thumbnail dimesions of the PDF
|
32
|
+
draw self.class.pdftoppm_path, "-singlefile", "-r", "72", "-png", file.path, &block
|
33
33
|
end
|
34
34
|
end
|
35
35
|
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
|