activestorage 7.0.8.1 → 7.2.2.1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +49 -360
- data/MIT-LICENSE +1 -1
- data/README.md +6 -6
- data/app/assets/javascripts/activestorage.esm.js +11 -7
- data/app/assets/javascripts/activestorage.js +12 -6
- data/app/controllers/active_storage/disk_controller.rb +4 -2
- data/app/controllers/active_storage/representations/proxy_controller.rb +1 -1
- data/app/controllers/concerns/active_storage/file_server.rb +4 -1
- data/app/javascript/activestorage/blob_record.js +4 -1
- data/app/javascript/activestorage/direct_upload.js +3 -2
- data/app/javascript/activestorage/index.js +3 -1
- data/app/javascript/activestorage/ujs.js +3 -3
- data/app/jobs/active_storage/analyze_job.rb +1 -1
- data/app/jobs/active_storage/mirror_job.rb +1 -1
- data/app/jobs/active_storage/preview_image_job.rb +16 -0
- data/app/jobs/active_storage/purge_job.rb +1 -1
- data/app/jobs/active_storage/transform_job.rb +12 -0
- data/app/models/active_storage/attachment.rb +101 -16
- data/app/models/active_storage/blob/analyzable.rb +4 -3
- data/app/models/active_storage/blob/identifiable.rb +1 -0
- data/app/models/active_storage/blob/representable.rb +15 -3
- data/app/models/active_storage/blob/servable.rb +22 -0
- data/app/models/active_storage/blob.rb +59 -72
- data/app/models/active_storage/current.rb +0 -10
- data/app/models/active_storage/filename.rb +2 -4
- data/app/models/active_storage/named_variant.rb +21 -0
- data/app/models/active_storage/preview.rb +23 -8
- data/app/models/active_storage/variant.rb +10 -7
- data/app/models/active_storage/variant_record.rb +0 -2
- data/app/models/active_storage/variant_with_record.rb +21 -7
- data/app/models/active_storage/variation.rb +5 -3
- data/config/routes.rb +6 -4
- data/db/migrate/20170806125915_create_active_storage_tables.rb +2 -2
- data/lib/active_storage/analyzer/audio_analyzer.rb +16 -4
- data/lib/active_storage/analyzer/image_analyzer/vips.rb +5 -9
- data/lib/active_storage/analyzer/image_analyzer.rb +2 -0
- data/lib/active_storage/analyzer/video_analyzer.rb +9 -3
- data/lib/active_storage/analyzer.rb +2 -0
- data/lib/active_storage/attached/changes/create_many.rb +8 -3
- data/lib/active_storage/attached/changes/create_one.rb +51 -4
- data/lib/active_storage/attached/changes/create_one_of_many.rb +5 -1
- data/lib/active_storage/attached/many.rb +5 -4
- data/lib/active_storage/attached/model.rb +96 -60
- data/lib/active_storage/attached/one.rb +5 -4
- data/lib/active_storage/attached.rb +2 -0
- data/lib/active_storage/deprecator.rb +7 -0
- data/lib/active_storage/engine.rb +7 -9
- data/lib/active_storage/fixture_set.rb +7 -1
- data/lib/active_storage/gem_version.rb +3 -3
- data/lib/active_storage/log_subscriber.rb +12 -0
- data/lib/active_storage/previewer/mupdf_previewer.rb +6 -2
- data/lib/active_storage/previewer/poppler_pdf_previewer.rb +6 -2
- data/lib/active_storage/previewer/video_previewer.rb +1 -1
- data/lib/active_storage/previewer.rb +8 -1
- data/lib/active_storage/reflection.rb +3 -3
- data/lib/active_storage/service/azure_storage_service.rb +2 -0
- data/lib/active_storage/service/disk_service.rb +2 -0
- data/lib/active_storage/service/gcs_service.rb +11 -20
- data/lib/active_storage/service/mirror_service.rb +10 -5
- data/lib/active_storage/service/s3_service.rb +2 -0
- data/lib/active_storage/service.rb +4 -2
- data/lib/active_storage/transformers/image_processing_transformer.rb +1 -1
- data/lib/active_storage/transformers/transformer.rb +2 -0
- data/lib/active_storage/version.rb +1 -1
- data/lib/active_storage.rb +5 -4
- metadata +23 -32
@@ -3,10 +3,54 @@
|
|
3
3
|
require "active_support/core_ext/object/try"
|
4
4
|
|
5
5
|
module ActiveStorage
|
6
|
+
# = Active Storage \Attached \Model
|
7
|
+
#
|
6
8
|
# Provides the class-level DSL for declaring an Active Record model's attachments.
|
7
9
|
module Attached::Model
|
8
10
|
extend ActiveSupport::Concern
|
9
11
|
|
12
|
+
##
|
13
|
+
# :method: *_attachment
|
14
|
+
#
|
15
|
+
# Returns the attachment for the +has_one_attached+.
|
16
|
+
#
|
17
|
+
# User.last.avatar_attachment
|
18
|
+
|
19
|
+
##
|
20
|
+
# :method: *_attachments
|
21
|
+
#
|
22
|
+
# Returns the attachments for the +has_many_attached+.
|
23
|
+
#
|
24
|
+
# Gallery.last.photos_attachments
|
25
|
+
|
26
|
+
##
|
27
|
+
# :method: *_blob
|
28
|
+
#
|
29
|
+
# Returns the blob for the +has_one_attached+ attachment.
|
30
|
+
#
|
31
|
+
# User.last.avatar_blob
|
32
|
+
|
33
|
+
##
|
34
|
+
# :method: *_blobs
|
35
|
+
#
|
36
|
+
# Returns the blobs for the +has_many_attached+ attachments.
|
37
|
+
#
|
38
|
+
# Gallery.last.photos_blobs
|
39
|
+
|
40
|
+
##
|
41
|
+
# :method: with_attached_*
|
42
|
+
#
|
43
|
+
# Includes the attached blobs in your query to avoid N+1 queries.
|
44
|
+
#
|
45
|
+
# If +ActiveStorage.track_variants+ is enabled, it will also include the
|
46
|
+
# variants record and their attached blobs.
|
47
|
+
#
|
48
|
+
# User.with_attached_avatar
|
49
|
+
#
|
50
|
+
# Use the plural form for +has_many_attached+:
|
51
|
+
#
|
52
|
+
# Gallery.with_attached_photos
|
53
|
+
|
10
54
|
class_methods do
|
11
55
|
# Specifies the relation between a single attachment and the model.
|
12
56
|
#
|
@@ -30,16 +74,24 @@ module ActiveStorage
|
|
30
74
|
# The system has been designed to having you go through the ActiveStorage::Attached::One
|
31
75
|
# proxy that provides the dynamic proxy to the associations and factory methods, like +attach+.
|
32
76
|
#
|
33
|
-
#
|
34
|
-
# (i.e. destroyed) whenever the record is destroyed.
|
77
|
+
# The +:dependent+ option defaults to +:purge_later+. This means the attachment will be
|
78
|
+
# purged (i.e. destroyed) in the background whenever the record is destroyed.
|
79
|
+
# If an ActiveJob::Backend queue adapter is not set in the application set it to
|
80
|
+
# +purge+ instead.
|
35
81
|
#
|
36
82
|
# If you need the attachment to use a service which differs from the globally configured one,
|
37
|
-
# pass the +:service+ option. For
|
83
|
+
# pass the +:service+ option. For example:
|
38
84
|
#
|
39
85
|
# class User < ActiveRecord::Base
|
40
86
|
# has_one_attached :avatar, service: :s3
|
41
87
|
# end
|
42
88
|
#
|
89
|
+
# +:service+ can also be specified as a proc, and it will be called with the model instance:
|
90
|
+
#
|
91
|
+
# class User < ActiveRecord::Base
|
92
|
+
# has_one_attached :avatar, service: ->(user) { user.in_europe_region? ? :s3_europe : :s3_usa }
|
93
|
+
# end
|
94
|
+
#
|
43
95
|
# If you need to enable +strict_loading+ to prevent lazy loading of attachment,
|
44
96
|
# pass the +:strict_loading+ option. You can do:
|
45
97
|
#
|
@@ -47,8 +99,12 @@ module ActiveStorage
|
|
47
99
|
# has_one_attached :avatar, strict_loading: true
|
48
100
|
# end
|
49
101
|
#
|
102
|
+
# Note: Active Storage relies on polymorphic associations, which in turn store class names in the database.
|
103
|
+
# When renaming classes that use <tt>has_one_attached</tt>, make sure to also update the class names in the
|
104
|
+
# <tt>active_storage_attachments.record_type</tt> polymorphic type column of
|
105
|
+
# the corresponding rows.
|
50
106
|
def has_one_attached(name, dependent: :purge_later, service: nil, strict_loading: false)
|
51
|
-
validate_service_configuration(
|
107
|
+
ActiveStorage::Blob.validate_service_configuration(service, self, name) unless service.is_a?(Proc)
|
52
108
|
|
53
109
|
generated_association_methods.class_eval <<-CODE, __FILE__, __LINE__ + 1
|
54
110
|
# frozen_string_literal: true
|
@@ -59,7 +115,7 @@ module ActiveStorage
|
|
59
115
|
|
60
116
|
def #{name}=(attachable)
|
61
117
|
attachment_changes["#{name}"] =
|
62
|
-
if attachable.nil?
|
118
|
+
if attachable.nil? || attachable == ""
|
63
119
|
ActiveStorage::Attached::Changes::DeleteOne.new("#{name}", self)
|
64
120
|
else
|
65
121
|
ActiveStorage::Attached::Changes::CreateOne.new("#{name}", self, attachable)
|
@@ -70,7 +126,16 @@ module ActiveStorage
|
|
70
126
|
has_one :"#{name}_attachment", -> { where(name: name) }, class_name: "ActiveStorage::Attachment", as: :record, inverse_of: :record, dependent: :destroy, strict_loading: strict_loading
|
71
127
|
has_one :"#{name}_blob", through: :"#{name}_attachment", class_name: "ActiveStorage::Blob", source: :blob, strict_loading: strict_loading
|
72
128
|
|
73
|
-
scope :"with_attached_#{name}", -> {
|
129
|
+
scope :"with_attached_#{name}", -> {
|
130
|
+
if ActiveStorage.track_variants
|
131
|
+
includes("#{name}_attachment": { blob: {
|
132
|
+
variant_records: { image_attachment: :blob },
|
133
|
+
preview_image_attachment: { blob: { variant_records: { image_attachment: :blob } } }
|
134
|
+
} })
|
135
|
+
else
|
136
|
+
includes("#{name}_attachment": :blob)
|
137
|
+
end
|
138
|
+
}
|
74
139
|
|
75
140
|
after_save { attachment_changes[name.to_s]&.save }
|
76
141
|
|
@@ -109,16 +174,24 @@ module ActiveStorage
|
|
109
174
|
# The system has been designed to having you go through the ActiveStorage::Attached::Many
|
110
175
|
# proxy that provides the dynamic proxy to the associations and factory methods, like +#attach+.
|
111
176
|
#
|
112
|
-
#
|
113
|
-
# (i.e. destroyed) whenever the record is destroyed.
|
177
|
+
# The +:dependent+ option defaults to +:purge_later+. This means the attachments will be
|
178
|
+
# purged (i.e. destroyed) in the background whenever the record is destroyed.
|
179
|
+
# If an ActiveJob::Backend queue adapter is not set in the application set it to
|
180
|
+
# +purge+ instead.
|
114
181
|
#
|
115
182
|
# If you need the attachment to use a service which differs from the globally configured one,
|
116
|
-
# pass the +:service+ option. For
|
183
|
+
# pass the +:service+ option. For example:
|
117
184
|
#
|
118
185
|
# class Gallery < ActiveRecord::Base
|
119
186
|
# has_many_attached :photos, service: :s3
|
120
187
|
# end
|
121
188
|
#
|
189
|
+
# +:service+ can also be specified as a proc, and it will be called with the model instance:
|
190
|
+
#
|
191
|
+
# class Gallery < ActiveRecord::Base
|
192
|
+
# has_many_attached :photos, service: ->(gallery) { gallery.personal? ? :personal_s3 : :s3 }
|
193
|
+
# end
|
194
|
+
#
|
122
195
|
# If you need to enable +strict_loading+ to prevent lazy loading of attachments,
|
123
196
|
# pass the +:strict_loading+ option. You can do:
|
124
197
|
#
|
@@ -126,8 +199,12 @@ module ActiveStorage
|
|
126
199
|
# has_many_attached :photos, strict_loading: true
|
127
200
|
# end
|
128
201
|
#
|
202
|
+
# Note: Active Storage relies on polymorphic associations, which in turn store class names in the database.
|
203
|
+
# When renaming classes that use <tt>has_many</tt>, make sure to also update the class names in the
|
204
|
+
# <tt>active_storage_attachments.record_type</tt> polymorphic type column of
|
205
|
+
# the corresponding rows.
|
129
206
|
def has_many_attached(name, dependent: :purge_later, service: nil, strict_loading: false)
|
130
|
-
validate_service_configuration(
|
207
|
+
ActiveStorage::Blob.validate_service_configuration(service, self, name) unless service.is_a?(Proc)
|
131
208
|
|
132
209
|
generated_association_methods.class_eval <<-CODE, __FILE__, __LINE__ + 1
|
133
210
|
# frozen_string_literal: true
|
@@ -138,57 +215,25 @@ module ActiveStorage
|
|
138
215
|
|
139
216
|
def #{name}=(attachables)
|
140
217
|
attachables = Array(attachables).compact_blank
|
218
|
+
pending_uploads = attachment_changes["#{name}"].try(:pending_uploads)
|
141
219
|
|
142
|
-
if
|
143
|
-
|
144
|
-
if attachables.none?
|
145
|
-
ActiveStorage::Attached::Changes::DeleteMany.new("#{name}", self)
|
146
|
-
else
|
147
|
-
ActiveStorage::Attached::Changes::CreateMany.new("#{name}", self, attachables)
|
148
|
-
end
|
220
|
+
attachment_changes["#{name}"] = if attachables.none?
|
221
|
+
ActiveStorage::Attached::Changes::DeleteMany.new("#{name}", self)
|
149
222
|
else
|
150
|
-
|
151
|
-
"config.active_storage.replace_on_assign_to_many is deprecated and will be removed in Rails 7.1. " \
|
152
|
-
"Make sure that your code works well with config.active_storage.replace_on_assign_to_many set to true before upgrading. " \
|
153
|
-
"To append new attachables to the Active Storage association, prefer using `attach`. " \
|
154
|
-
"Using association setter would result in purging the existing attached attachments and replacing them with new ones."
|
155
|
-
|
156
|
-
if attachables.any?
|
157
|
-
attachment_changes["#{name}"] =
|
158
|
-
ActiveStorage::Attached::Changes::CreateMany.new("#{name}", self, #{name}.blobs + attachables)
|
159
|
-
end
|
223
|
+
ActiveStorage::Attached::Changes::CreateMany.new("#{name}", self, attachables, pending_uploads: pending_uploads)
|
160
224
|
end
|
161
225
|
end
|
162
226
|
CODE
|
163
227
|
|
164
|
-
has_many :"#{name}_attachments", -> { where(name: name) }, as: :record, class_name: "ActiveStorage::Attachment", inverse_of: :record, dependent: :destroy, strict_loading: strict_loading
|
165
|
-
def purge
|
166
|
-
deprecate(:purge)
|
167
|
-
each(&:purge)
|
168
|
-
reset
|
169
|
-
end
|
170
|
-
|
171
|
-
def purge_later
|
172
|
-
deprecate(:purge_later)
|
173
|
-
each(&:purge_later)
|
174
|
-
reset
|
175
|
-
end
|
176
|
-
|
177
|
-
private
|
178
|
-
def deprecate(action)
|
179
|
-
reflection_name = proxy_association.reflection.name
|
180
|
-
attached_name = reflection_name.to_s.partition("_").first
|
181
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
182
|
-
Calling `#{action}` from `#{reflection_name}` is deprecated and will be removed in Rails 7.1.
|
183
|
-
To migrate to Rails 7.1's behavior call `#{action}` from `#{attached_name}` instead: `#{attached_name}.#{action}`.
|
184
|
-
MSG
|
185
|
-
end
|
186
|
-
end
|
228
|
+
has_many :"#{name}_attachments", -> { where(name: name) }, as: :record, class_name: "ActiveStorage::Attachment", inverse_of: :record, dependent: :destroy, strict_loading: strict_loading
|
187
229
|
has_many :"#{name}_blobs", through: :"#{name}_attachments", class_name: "ActiveStorage::Blob", source: :blob, strict_loading: strict_loading
|
188
230
|
|
189
231
|
scope :"with_attached_#{name}", -> {
|
190
232
|
if ActiveStorage.track_variants
|
191
|
-
includes("#{name}_attachments": { blob:
|
233
|
+
includes("#{name}_attachments": { blob: {
|
234
|
+
variant_records: { image_attachment: :blob },
|
235
|
+
preview_image_attachment: { blob: { variant_records: { image_attachment: :blob } } }
|
236
|
+
} })
|
192
237
|
else
|
193
238
|
includes("#{name}_attachments": :blob)
|
194
239
|
end
|
@@ -208,15 +253,6 @@ module ActiveStorage
|
|
208
253
|
yield reflection if block_given?
|
209
254
|
ActiveRecord::Reflection.add_attachment_reflection(self, name, reflection)
|
210
255
|
end
|
211
|
-
|
212
|
-
private
|
213
|
-
def validate_service_configuration(association_name, service)
|
214
|
-
if service.present?
|
215
|
-
ActiveStorage::Blob.services.fetch(service) do
|
216
|
-
raise ArgumentError, "Cannot configure service :#{service} for #{name}##{association_name}"
|
217
|
-
end
|
218
|
-
end
|
219
|
-
end
|
220
256
|
end
|
221
257
|
|
222
258
|
def attachment_changes # :nodoc:
|
@@ -1,6 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveStorage
|
4
|
+
# = Active Storage \Attached \One
|
5
|
+
#
|
4
6
|
# Representation of a single attachment to a model.
|
5
7
|
class Attached::One < Attached
|
6
8
|
##
|
@@ -54,12 +56,11 @@ module ActiveStorage
|
|
54
56
|
# person.avatar.attach(io: File.open("/path/to/face.jpg"), filename: "face.jpg", content_type: "image/jpeg")
|
55
57
|
# person.avatar.attach(avatar_blob) # ActiveStorage::Blob object
|
56
58
|
def attach(attachable)
|
59
|
+
record.public_send("#{name}=", attachable)
|
57
60
|
if record.persisted? && !record.changed?
|
58
|
-
record.
|
59
|
-
record.save
|
60
|
-
else
|
61
|
-
record.public_send("#{name}=", attachable)
|
61
|
+
return if !record.save
|
62
62
|
end
|
63
|
+
record.public_send("#{name}")
|
63
64
|
end
|
64
65
|
|
65
66
|
# Returns +true+ if an attachment has been made.
|
@@ -3,6 +3,8 @@
|
|
3
3
|
require "active_support/core_ext/module/delegation"
|
4
4
|
|
5
5
|
module ActiveStorage
|
6
|
+
# = Active Storage \Attached
|
7
|
+
#
|
6
8
|
# Abstract base class for the concrete ActiveStorage::Attached::One and ActiveStorage::Attached::Many
|
7
9
|
# classes that both provide proxy access to the blob association for a record.
|
8
10
|
class Attached
|
@@ -35,9 +35,7 @@ module ActiveStorage
|
|
35
35
|
config.active_storage.variable_content_types = %w(
|
36
36
|
image/png
|
37
37
|
image/gif
|
38
|
-
image/jpg
|
39
38
|
image/jpeg
|
40
|
-
image/pjpeg
|
41
39
|
image/tiff
|
42
40
|
image/bmp
|
43
41
|
image/vnd.adobe.photoshop
|
@@ -51,13 +49,11 @@ module ActiveStorage
|
|
51
49
|
config.active_storage.web_image_content_types = %w(
|
52
50
|
image/png
|
53
51
|
image/jpeg
|
54
|
-
image/jpg
|
55
52
|
image/gif
|
56
53
|
)
|
57
54
|
|
58
55
|
config.active_storage.content_types_to_serve_as_binary = %w(
|
59
56
|
text/html
|
60
|
-
text/javascript
|
61
57
|
image/svg+xml
|
62
58
|
application/postscript
|
63
59
|
application/x-shockwave-flash
|
@@ -69,9 +65,10 @@ module ActiveStorage
|
|
69
65
|
)
|
70
66
|
|
71
67
|
config.active_storage.content_types_allowed_inline = %w(
|
68
|
+
image/webp
|
69
|
+
image/avif
|
72
70
|
image/png
|
73
71
|
image/gif
|
74
|
-
image/jpg
|
75
72
|
image/jpeg
|
76
73
|
image/tiff
|
77
74
|
image/bmp
|
@@ -82,6 +79,10 @@ module ActiveStorage
|
|
82
79
|
|
83
80
|
config.eager_load_namespaces << ActiveStorage
|
84
81
|
|
82
|
+
initializer "active_storage.deprecator", before: :load_environment_config do |app|
|
83
|
+
app.deprecators[:active_storage] = ActiveStorage.deprecator
|
84
|
+
end
|
85
|
+
|
85
86
|
initializer "active_storage.configs" do
|
86
87
|
config.after_initialize do |app|
|
87
88
|
ActiveStorage.logger = app.config.active_storage.logger || Rails.logger
|
@@ -111,15 +112,12 @@ module ActiveStorage
|
|
111
112
|
ActiveStorage.variable_content_types = app.config.active_storage.variable_content_types || []
|
112
113
|
ActiveStorage.web_image_content_types = app.config.active_storage.web_image_content_types || []
|
113
114
|
ActiveStorage.content_types_to_serve_as_binary = app.config.active_storage.content_types_to_serve_as_binary || []
|
115
|
+
ActiveStorage.touch_attachment_records = app.config.active_storage.touch_attachment_records != false
|
114
116
|
ActiveStorage.service_urls_expire_in = app.config.active_storage.service_urls_expire_in || 5.minutes
|
115
117
|
ActiveStorage.urls_expire_in = app.config.active_storage.urls_expire_in
|
116
118
|
ActiveStorage.content_types_allowed_inline = app.config.active_storage.content_types_allowed_inline || []
|
117
119
|
ActiveStorage.binary_content_type = app.config.active_storage.binary_content_type || "application/octet-stream"
|
118
120
|
ActiveStorage.video_preview_arguments = app.config.active_storage.video_preview_arguments || "-y -vframes 1 -f image2"
|
119
|
-
|
120
|
-
ActiveStorage.silence_invalid_content_types_warning = app.config.active_storage.silence_invalid_content_types_warning || false
|
121
|
-
|
122
|
-
ActiveStorage.replace_on_assign_to_many = app.config.active_storage.replace_on_assign_to_many || false
|
123
121
|
ActiveStorage.track_variants = app.config.active_storage.track_variants || false
|
124
122
|
end
|
125
123
|
end
|
@@ -4,6 +4,8 @@ require "active_support/testing/file_fixtures"
|
|
4
4
|
require "active_record/secure_token"
|
5
5
|
|
6
6
|
module ActiveStorage
|
7
|
+
# = Active Storage \FixtureSet
|
8
|
+
#
|
7
9
|
# Fixtures are a way of organizing data that you want to test against; in
|
8
10
|
# short, sample data.
|
9
11
|
#
|
@@ -24,9 +26,13 @@ module ActiveStorage
|
|
24
26
|
# has_one_attached :thumbnail
|
25
27
|
# end
|
26
28
|
#
|
29
|
+
# <code></code>
|
30
|
+
#
|
27
31
|
# # fixtures/active_storage/blobs.yml
|
28
32
|
# first_thumbnail_blob: <%= ActiveStorage::FixtureSet.blob filename: "first.png" %>
|
29
33
|
#
|
34
|
+
# <code></code>
|
35
|
+
#
|
30
36
|
# # fixtures/active_storage/attachments.yml
|
31
37
|
# first_thumbnail_attachment:
|
32
38
|
# name: thumbnail
|
@@ -46,7 +52,7 @@ module ActiveStorage
|
|
46
52
|
#
|
47
53
|
# === Examples
|
48
54
|
#
|
49
|
-
# # tests/fixtures/
|
55
|
+
# # tests/fixtures/active_storage/blobs.yml
|
50
56
|
# second_thumbnail_blob: <%= ActiveStorage::FixtureSet.blob(
|
51
57
|
# filename: "second.svg",
|
52
58
|
# ) %>
|
@@ -1,15 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveStorage
|
4
|
-
# Returns the currently loaded version of Active Storage as a
|
4
|
+
# Returns the currently loaded version of Active Storage as a +Gem::Version+.
|
5
5
|
def self.gem_version
|
6
6
|
Gem::Version.new VERSION::STRING
|
7
7
|
end
|
8
8
|
|
9
9
|
module VERSION
|
10
10
|
MAJOR = 7
|
11
|
-
MINOR =
|
12
|
-
TINY =
|
11
|
+
MINOR = 2
|
12
|
+
TINY = 2
|
13
13
|
PRE = "1"
|
14
14
|
|
15
15
|
STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
|
@@ -9,34 +9,46 @@ module ActiveStorage
|
|
9
9
|
message += " (checksum: #{event.payload[:checksum]})" if event.payload[:checksum]
|
10
10
|
info event, color(message, GREEN)
|
11
11
|
end
|
12
|
+
subscribe_log_level :service_upload, :info
|
12
13
|
|
13
14
|
def service_download(event)
|
14
15
|
info event, color("Downloaded file from key: #{key_in(event)}", BLUE)
|
15
16
|
end
|
17
|
+
subscribe_log_level :service_download, :info
|
16
18
|
|
17
19
|
alias_method :service_streaming_download, :service_download
|
18
20
|
|
21
|
+
def preview(event)
|
22
|
+
info event, color("Previewed file from key: #{key_in(event)}", BLUE)
|
23
|
+
end
|
24
|
+
subscribe_log_level :preview, :info
|
25
|
+
|
19
26
|
def service_delete(event)
|
20
27
|
info event, color("Deleted file from key: #{key_in(event)}", RED)
|
21
28
|
end
|
29
|
+
subscribe_log_level :service_delete, :info
|
22
30
|
|
23
31
|
def service_delete_prefixed(event)
|
24
32
|
info event, color("Deleted files by key prefix: #{event.payload[:prefix]}", RED)
|
25
33
|
end
|
34
|
+
subscribe_log_level :service_delete_prefixed, :info
|
26
35
|
|
27
36
|
def service_exist(event)
|
28
37
|
debug event, color("Checked if file exists at key: #{key_in(event)} (#{event.payload[:exist] ? "yes" : "no"})", BLUE)
|
29
38
|
end
|
39
|
+
subscribe_log_level :service_exist, :debug
|
30
40
|
|
31
41
|
def service_url(event)
|
32
42
|
debug event, color("Generated URL for file at key: #{key_in(event)} (#{event.payload[:url]})", BLUE)
|
33
43
|
end
|
44
|
+
subscribe_log_level :service_url, :debug
|
34
45
|
|
35
46
|
def service_mirror(event)
|
36
47
|
message = "Mirrored file at key: #{key_in(event)}"
|
37
48
|
message += " (checksum: #{event.payload[:checksum]})" if event.payload[:checksum]
|
38
49
|
debug event, color(message, GREEN)
|
39
50
|
end
|
51
|
+
subscribe_log_level :service_mirror, :debug
|
40
52
|
|
41
53
|
def logger
|
42
54
|
ActiveStorage.logger
|
@@ -4,7 +4,11 @@ module ActiveStorage
|
|
4
4
|
class Previewer::MuPDFPreviewer < Previewer
|
5
5
|
class << self
|
6
6
|
def accept?(blob)
|
7
|
-
blob.content_type
|
7
|
+
pdf?(blob.content_type) && mutool_exists?
|
8
|
+
end
|
9
|
+
|
10
|
+
def pdf?(content_type)
|
11
|
+
Marcel::Magic.child? content_type, "application/pdf"
|
8
12
|
end
|
9
13
|
|
10
14
|
def mutool_path
|
@@ -12,7 +16,7 @@ module ActiveStorage
|
|
12
16
|
end
|
13
17
|
|
14
18
|
def mutool_exists?
|
15
|
-
return @mutool_exists
|
19
|
+
return @mutool_exists unless @mutool_exists.nil?
|
16
20
|
|
17
21
|
system mutool_path, out: File::NULL, err: File::NULL
|
18
22
|
|
@@ -4,7 +4,11 @@ module ActiveStorage
|
|
4
4
|
class Previewer::PopplerPDFPreviewer < Previewer
|
5
5
|
class << self
|
6
6
|
def accept?(blob)
|
7
|
-
blob.content_type
|
7
|
+
pdf?(blob.content_type) && pdftoppm_exists?
|
8
|
+
end
|
9
|
+
|
10
|
+
def pdf?(content_type)
|
11
|
+
Marcel::Magic.child? content_type, "application/pdf"
|
8
12
|
end
|
9
13
|
|
10
14
|
def pdftoppm_path
|
@@ -12,7 +16,7 @@ module ActiveStorage
|
|
12
16
|
end
|
13
17
|
|
14
18
|
def pdftoppm_exists?
|
15
|
-
return @pdftoppm_exists
|
19
|
+
return @pdftoppm_exists unless @pdftoppm_exists.nil?
|
16
20
|
|
17
21
|
@pdftoppm_exists = system(pdftoppm_path, "-v", out: File::NULL, err: File::NULL)
|
18
22
|
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveStorage
|
4
|
+
# = Active Storage \Previewer
|
5
|
+
#
|
4
6
|
# This is an abstract base class for previewers, which generate images from blobs. See
|
5
7
|
# ActiveStorage::Previewer::MuPDFPreviewer and ActiveStorage::Previewer::VideoPreviewer for
|
6
8
|
# examples of concrete subclasses.
|
@@ -65,7 +67,12 @@ module ActiveStorage
|
|
65
67
|
end
|
66
68
|
|
67
69
|
def instrument(operation, payload = {}, &block)
|
68
|
-
ActiveSupport::Notifications.instrument "#{operation}.active_storage", payload, &block
|
70
|
+
ActiveSupport::Notifications.instrument "#{operation}.active_storage", payload.merge(service: service_name), &block
|
71
|
+
end
|
72
|
+
|
73
|
+
def service_name
|
74
|
+
# ActiveStorage::Service::DiskService => Disk
|
75
|
+
blob.service.class.to_s.split("::").third.remove("Service")
|
69
76
|
end
|
70
77
|
|
71
78
|
def capture(*argv, to:)
|
@@ -4,11 +4,11 @@ module ActiveStorage
|
|
4
4
|
module Reflection
|
5
5
|
class HasAttachedReflection < ActiveRecord::Reflection::MacroReflection # :nodoc:
|
6
6
|
def variant(name, transformations)
|
7
|
-
|
7
|
+
named_variants[name] = NamedVariant.new(transformations)
|
8
8
|
end
|
9
9
|
|
10
|
-
def
|
11
|
-
@
|
10
|
+
def named_variants
|
11
|
+
@named_variants ||= {}
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
@@ -7,6 +7,8 @@ require "azure/storage/blob"
|
|
7
7
|
require "azure/storage/common/core/auth/shared_access_signature"
|
8
8
|
|
9
9
|
module ActiveStorage
|
10
|
+
# = Active Storage \Azure Storage \Service
|
11
|
+
#
|
10
12
|
# Wraps the Microsoft Azure Storage Blob Service as an Active Storage service.
|
11
13
|
# See ActiveStorage::Service for the generic API documentation that applies to all services.
|
12
14
|
class Service::AzureStorageService < Service
|
@@ -6,6 +6,8 @@ require "openssl"
|
|
6
6
|
require "active_support/core_ext/numeric/bytes"
|
7
7
|
|
8
8
|
module ActiveStorage
|
9
|
+
# = Active Storage \Disk \Service
|
10
|
+
#
|
9
11
|
# Wraps a local disk path as an Active Storage service. See ActiveStorage::Service for the generic API
|
10
12
|
# documentation that applies to all services.
|
11
13
|
class Service::DiskService < Service
|
@@ -5,6 +5,8 @@ require "google/apis/iamcredentials_v1"
|
|
5
5
|
require "google/cloud/storage"
|
6
6
|
|
7
7
|
module ActiveStorage
|
8
|
+
# = Active Storage \GCS \Service
|
9
|
+
#
|
8
10
|
# Wraps the Google Cloud Storage as an Active Storage service. See ActiveStorage::Service for the generic API
|
9
11
|
# documentation that applies to all services.
|
10
12
|
class Service::GCSService < Service
|
@@ -195,26 +197,15 @@ module ActiveStorage
|
|
195
197
|
end
|
196
198
|
|
197
199
|
def issuer
|
198
|
-
@issuer ||=
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
response = http.request(request)
|
208
|
-
rescue SocketError
|
209
|
-
raise MetadataServerNotFoundError
|
210
|
-
end
|
211
|
-
|
212
|
-
if response.is_a?(Net::HTTPSuccess)
|
213
|
-
response.body
|
214
|
-
else
|
215
|
-
raise MetadataServerError
|
216
|
-
end
|
217
|
-
end
|
200
|
+
@issuer ||= @config[:gsa_email].presence || email_from_metadata_server
|
201
|
+
end
|
202
|
+
|
203
|
+
def email_from_metadata_server
|
204
|
+
env = Google::Cloud.env
|
205
|
+
raise MetadataServerNotFoundError if !env.metadata?
|
206
|
+
|
207
|
+
email = env.lookup_metadata("instance", "service-accounts/default/email")
|
208
|
+
email.presence or raise MetadataServerError
|
218
209
|
end
|
219
210
|
|
220
211
|
def signer
|
@@ -3,6 +3,8 @@
|
|
3
3
|
require "active_support/core_ext/module/delegation"
|
4
4
|
|
5
5
|
module ActiveStorage
|
6
|
+
# = Active Storage Mirror \Service
|
7
|
+
#
|
6
8
|
# Wraps a set of mirror services and provides a single ActiveStorage::Service object that will all
|
7
9
|
# have the files uploaded to them. A +primary+ service is designated to answer calls to:
|
8
10
|
# * +download+
|
@@ -30,13 +32,13 @@ module ActiveStorage
|
|
30
32
|
@primary, @mirrors = primary, mirrors
|
31
33
|
end
|
32
34
|
|
33
|
-
# Upload the +io+ to the +key+ specified to all services.
|
35
|
+
# Upload the +io+ to the +key+ specified to all services. The upload to the primary service is done synchronously
|
36
|
+
# whereas the upload to the mirrors is done asynchronously. If a +checksum+ is provided, all services will
|
34
37
|
# ensure a match when the upload has completed or raise an ActiveStorage::IntegrityError.
|
35
38
|
def upload(key, io, checksum: nil, **options)
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
end
|
39
|
+
io.rewind
|
40
|
+
primary.upload key, io, checksum: checksum, **options
|
41
|
+
mirror_later key, checksum: checksum
|
40
42
|
end
|
41
43
|
|
42
44
|
# Delete the file at the +key+ on all services.
|
@@ -49,6 +51,9 @@ module ActiveStorage
|
|
49
51
|
perform_across_services :delete_prefixed, prefix
|
50
52
|
end
|
51
53
|
|
54
|
+
def mirror_later(key, checksum:) # :nodoc:
|
55
|
+
ActiveStorage::MirrorJob.perform_later key, checksum: checksum
|
56
|
+
end
|
52
57
|
|
53
58
|
# Copy the file at the +key+ from the primary service to each of the mirrors where it doesn't already exist.
|
54
59
|
def mirror(key, checksum:)
|
@@ -6,6 +6,8 @@ require "aws-sdk-s3"
|
|
6
6
|
require "active_support/core_ext/numeric/bytes"
|
7
7
|
|
8
8
|
module ActiveStorage
|
9
|
+
# = Active Storage \S3 \Service
|
10
|
+
#
|
9
11
|
# Wraps the Amazon Simple Storage Service (S3) as an Active Storage service.
|
10
12
|
# See ActiveStorage::Service for the generic API documentation that applies to all services.
|
11
13
|
class Service::S3Service < Service
|