activestorage 7.1.5.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 +29 -284
- data/app/models/active_storage/attachment.rb +4 -4
- data/app/models/active_storage/blob.rb +35 -12
- data/app/models/active_storage/filename.rb +0 -4
- data/app/models/active_storage/preview.rb +14 -6
- data/db/migrate/20170806125915_create_active_storage_tables.rb +1 -1
- data/lib/active_storage/analyzer/image_analyzer/vips.rb +5 -9
- data/lib/active_storage/analyzer/video_analyzer.rb +6 -2
- data/lib/active_storage/attached/changes/create_one.rb +6 -1
- data/lib/active_storage/attached/changes/create_one_of_many.rb +5 -1
- data/lib/active_storage/attached/model.rb +24 -21
- data/lib/active_storage/engine.rb +3 -9
- data/lib/active_storage/gem_version.rb +2 -2
- 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/transformers/image_processing_transformer.rb +1 -1
- data/lib/active_storage.rb +1 -16
- metadata +13 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 19f4fa25c348a39b38b18a049dd123c5a0c6f80d70e05cdfc4790c7e0dbf96d1
|
4
|
+
data.tar.gz: 48ba490e74129a1495ed0b3249730bfeba7b12f916e787849e7cfa4f81235bf9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6656a5f10b464e63d86f0e4fc60984735e522d56789f93ce4f0d6ec4684b0b7e6a449f14af01a92e5929b1a4854f283b0bf89b37fe67ecb5d8cc207430b81c71
|
7
|
+
data.tar.gz: a8fe146a25f52b241de32978f344a2303ad5221f05306a57776337194ba67aa2691c715790131056dec44dfe21cb26b7df1fe33fef5d09efba3ff5f226b83e58
|
data/CHANGELOG.md
CHANGED
@@ -1,51 +1,50 @@
|
|
1
|
-
## Rails 7.
|
1
|
+
## Rails 7.2.2.1 (December 10, 2024) ##
|
2
2
|
|
3
3
|
* No changes.
|
4
4
|
|
5
5
|
|
6
|
-
## Rails 7.
|
6
|
+
## Rails 7.2.2 (October 30, 2024) ##
|
7
7
|
|
8
8
|
* No changes.
|
9
9
|
|
10
10
|
|
11
|
-
## Rails 7.1.
|
11
|
+
## Rails 7.2.1.2 (October 23, 2024) ##
|
12
12
|
|
13
13
|
* No changes.
|
14
14
|
|
15
15
|
|
16
|
-
## Rails 7.1.
|
16
|
+
## Rails 7.2.1.1 (October 15, 2024) ##
|
17
17
|
|
18
18
|
* No changes.
|
19
19
|
|
20
20
|
|
21
|
-
## Rails 7.1
|
22
|
-
|
23
|
-
* Fixes race condition for multiple preprocessed video variants.
|
24
|
-
|
25
|
-
*Justin Searls*
|
26
|
-
|
27
|
-
|
28
|
-
## Rails 7.1.3.4 (June 04, 2024) ##
|
21
|
+
## Rails 7.2.1 (August 22, 2024) ##
|
29
22
|
|
30
23
|
* No changes.
|
31
24
|
|
32
25
|
|
33
|
-
## Rails 7.
|
26
|
+
## Rails 7.2.0 (August 09, 2024) ##
|
34
27
|
|
35
|
-
*
|
28
|
+
* Remove deprecated `config.active_storage.silence_invalid_content_types_warning`.
|
36
29
|
|
30
|
+
*Rafael Mendonça França*
|
37
31
|
|
38
|
-
|
32
|
+
* Remove deprecated `config.active_storage.replace_on_assign_to_many`.
|
39
33
|
|
40
|
-
*
|
34
|
+
*Rafael Mendonça França*
|
41
35
|
|
36
|
+
* Add support for custom `key` in `ActiveStorage::Blob#compose`.
|
42
37
|
|
43
|
-
|
38
|
+
*Elvin Efendiev*
|
44
39
|
|
45
|
-
*
|
40
|
+
* Add `image/webp` to `config.active_storage.web_image_content_types` when `load_defaults "7.2"`
|
41
|
+
is set.
|
42
|
+
|
43
|
+
*Lewis Buckley*
|
46
44
|
|
45
|
+
* Fix JSON-encoding of `ActiveStorage::Filename` instances.
|
47
46
|
|
48
|
-
|
47
|
+
*Jonathan del Strother*
|
49
48
|
|
50
49
|
* Fix N+1 query when fetching preview images for non-image assets.
|
51
50
|
|
@@ -66,16 +65,20 @@
|
|
66
65
|
|
67
66
|
*Chedli Bourguiba*
|
68
67
|
|
69
|
-
* Fix direct upload forms when submit button contains nested elements.
|
70
|
-
|
71
|
-
*Marc Köhlbrugge*
|
72
|
-
|
73
68
|
* When using the `preprocessed: true` option, avoid enqueuing transform jobs
|
74
69
|
for blobs that are not representable.
|
75
70
|
|
76
71
|
*Chedli Bourguiba*
|
77
72
|
|
73
|
+
* Prevent `ActiveStorage::Blob#preview` to generate a variant if an empty variation is passed.
|
74
|
+
|
75
|
+
Calls to `#url`, `#key` or `#download` will now use the original preview
|
76
|
+
image instead of generating a variant with the exact same dimensions.
|
77
|
+
|
78
|
+
*Chedli Bourguiba*
|
79
|
+
|
78
80
|
* Process preview image variant when calling `ActiveStorage::Preview#processed`.
|
81
|
+
|
79
82
|
For example, `attached_pdf.preview(:thumb).processed` will now immediately
|
80
83
|
generate the full-sized preview image and the `:thumb` variant of it.
|
81
84
|
Previously, the `:thumb` variant would not be generated until a further call
|
@@ -93,266 +96,8 @@
|
|
93
96
|
|
94
97
|
*Nico Wenterodt*
|
95
98
|
|
99
|
+
* Allow accepting `service` as a proc as well in `has_one_attached` and `has_many_attached`.
|
96
100
|
|
97
|
-
|
98
|
-
|
99
|
-
* No changes.
|
100
|
-
|
101
|
-
|
102
|
-
## Rails 7.1.1 (October 11, 2023) ##
|
103
|
-
|
104
|
-
* No changes.
|
105
|
-
|
106
|
-
|
107
|
-
## Rails 7.1.0 (October 05, 2023) ##
|
108
|
-
|
109
|
-
* No changes.
|
110
|
-
|
111
|
-
|
112
|
-
## Rails 7.1.0.rc2 (October 01, 2023) ##
|
113
|
-
|
114
|
-
* No changes.
|
115
|
-
|
116
|
-
|
117
|
-
## Rails 7.1.0.rc1 (September 27, 2023) ##
|
118
|
-
|
119
|
-
* Add `expires_at` option to `ActiveStorage::Blob#signed_id`.
|
120
|
-
|
121
|
-
```ruby
|
122
|
-
rails_blob_path(user.avatar, disposition: "attachment", expires_at: 30.minutes.from_now)
|
123
|
-
<%= image_tag rails_blob_path(user.avatar.variant(resize: "100x100"), expires_at: 30.minutes.from_now) %>
|
124
|
-
```
|
125
|
-
|
126
|
-
*Aki*
|
127
|
-
|
128
|
-
* Allow attaching File and Pathname when assigning attributes, e.g.
|
129
|
-
|
130
|
-
```ruby
|
131
|
-
User.create!(avatar: File.open("image.jpg"))
|
132
|
-
User.create!(avatar: file_fixture("image.jpg"))
|
133
|
-
```
|
134
|
-
|
135
|
-
*Dorian Marié*
|
136
|
-
|
137
|
-
|
138
|
-
## Rails 7.1.0.beta1 (September 13, 2023) ##
|
139
|
-
|
140
|
-
* Disables the session in `ActiveStorage::Blobs::ProxyController`
|
141
|
-
and `ActiveStorage::Representations::ProxyController`
|
142
|
-
in order to allow caching by default in some CDNs as CloudFlare
|
143
|
-
|
144
|
-
Fixes #44136
|
145
|
-
|
146
|
-
*Bruno Prieto*
|
147
|
-
|
148
|
-
* Add `tags` to `ActiveStorage::Analyzer::AudioAnalyzer` output
|
149
|
-
|
150
|
-
*Keaton Roux*
|
151
|
-
|
152
|
-
* Add an option to preprocess variants
|
153
|
-
|
154
|
-
ActiveStorage variants are processed on the fly when they are needed but
|
155
|
-
sometimes we're sure that they are accessed and want to processed them
|
156
|
-
upfront.
|
157
|
-
|
158
|
-
`preprocessed` option is added when declaring variants.
|
159
|
-
|
160
|
-
```
|
161
|
-
class User < ApplicationRecord
|
162
|
-
has_one_attached :avatar do |attachable|
|
163
|
-
attachable.variant :thumb, resize_to_limit: [100, 100], preprocessed: true
|
164
|
-
end
|
165
|
-
end
|
166
|
-
```
|
167
|
-
|
168
|
-
*Shouichi Kamiya*
|
169
|
-
|
170
|
-
* Fix variants not included when eager loading multiple records containing a single attachment
|
171
|
-
|
172
|
-
When using the `with_attached_#{name}` scope for a `has_one_attached` relation,
|
173
|
-
attachment variants were not eagerly loaded.
|
174
|
-
|
175
|
-
*Russell Porter*
|
176
|
-
|
177
|
-
* Allow an ActiveStorage attachment to be removed via a form post
|
178
|
-
|
179
|
-
Attachments can already be removed by updating the attachment to be nil such as:
|
180
|
-
```ruby
|
181
|
-
User.find(params[:id]).update!(avatar: nil)
|
182
|
-
```
|
183
|
-
|
184
|
-
However, a form cannot post a nil param, it can only post an empty string. But, posting an
|
185
|
-
empty string would result in an `ActiveSupport::MessageVerifier::InvalidSignature: mismatched digest`
|
186
|
-
error being raised, because it's being treated as a signed blob id.
|
187
|
-
|
188
|
-
Now, nil and an empty string are treated as a delete, which allows attachments to be removed via:
|
189
|
-
```ruby
|
190
|
-
User.find(params[:id]).update!(params.require(:user).permit(:avatar))
|
191
|
-
|
192
|
-
```
|
193
|
-
|
194
|
-
*Nate Matykiewicz*
|
195
|
-
|
196
|
-
* Remove mini_mime usage in favour of marcel.
|
197
|
-
|
198
|
-
We have two libraries that are have similar usage. This change removes
|
199
|
-
dependency on mini_mime and makes use of similar methods from marcel.
|
200
|
-
|
201
|
-
*Vipul A M*
|
202
|
-
|
203
|
-
* Allow destroying active storage variants
|
204
|
-
|
205
|
-
```ruby
|
206
|
-
User.first.avatar.variant(resize_to_limit: [100, 100]).destroy
|
207
|
-
```
|
208
|
-
|
209
|
-
*Shouichi Kamiya*, *Yuichiro NAKAGAWA*, *Ryohei UEDA*
|
210
|
-
|
211
|
-
* Add `sample_rate` to `ActiveStorage::Analyzer::AudioAnalyzer` output
|
212
|
-
|
213
|
-
*Matija Čupić*
|
214
|
-
|
215
|
-
* Remove deprecated `purge` and `purge_later` methods from the attachments association.
|
216
|
-
|
217
|
-
*Rafael Mendonça França*
|
218
|
-
|
219
|
-
* Remove deprecated behavior when assigning to a collection of attachments.
|
220
|
-
|
221
|
-
Instead of appending to the collection, the collection is now replaced.
|
222
|
-
|
223
|
-
*Rafael Mendonça França*
|
224
|
-
|
225
|
-
* Remove deprecated `ActiveStorage::Current#host` and `ActiveStorage::Current#host=` methods.
|
226
|
-
|
227
|
-
*Rafael Mendonça França*
|
228
|
-
|
229
|
-
* Remove deprecated invalid default content types in Active Storage configurations.
|
230
|
-
|
231
|
-
*Rafael Mendonça França*
|
232
|
-
|
233
|
-
* Add missing preview event to `ActiveStorage::LogSubscriber`
|
234
|
-
|
235
|
-
A `preview` event is being instrumented in `ActiveStorage::Previewer`.
|
236
|
-
However it was not added inside ActiveStorage's LogSubscriber class.
|
237
|
-
|
238
|
-
This will allow to have logs for when a preview happens
|
239
|
-
in the same fashion as all other ActiveStorage events such as
|
240
|
-
`upload` and `download` inside `Rails.logger`.
|
241
|
-
|
242
|
-
*Chedli Bourguiba*
|
243
|
-
|
244
|
-
* Fix retrieving rotation value from FFmpeg on version 5.0+.
|
245
|
-
|
246
|
-
In FFmpeg version 5.0+ the rotation value has been removed from tags.
|
247
|
-
Instead the value can be found in side_data_list. Along with
|
248
|
-
this update it's possible to have values of -90, -270 to denote the video
|
249
|
-
has been rotated.
|
250
|
-
|
251
|
-
*Haroon Ahmed*
|
252
|
-
|
253
|
-
* Touch all corresponding model records after ActiveStorage::Blob is analyzed
|
254
|
-
|
255
|
-
This fixes a race condition where a record can be requested and have a cache entry built, before
|
256
|
-
the initial `analyze_later` completes, which will not be invalidated until something else
|
257
|
-
updates the record. This also invalidates cache entries when a blob is re-analyzed, which
|
258
|
-
is helpful if a bug is fixed in an analyzer or a new analyzer is added.
|
259
|
-
|
260
|
-
*Nate Matykiewicz*
|
261
|
-
|
262
|
-
* Add ability to use pre-defined variants when calling `preview` or
|
263
|
-
`representation` on an attachment.
|
264
|
-
|
265
|
-
```ruby
|
266
|
-
class User < ActiveRecord::Base
|
267
|
-
has_one_attached :file do |attachable|
|
268
|
-
attachable.variant :thumb, resize_to_limit: [100, 100]
|
269
|
-
end
|
270
|
-
end
|
271
|
-
|
272
|
-
<%= image_tag user.file.representation(:thumb) %>
|
273
|
-
```
|
274
|
-
|
275
|
-
*Richard Böhme*
|
276
|
-
|
277
|
-
* Method `attach` always returns the attachments except when the record
|
278
|
-
is persisted, unchanged, and saving it fails, in which case it returns `nil`.
|
279
|
-
|
280
|
-
*Santiago Bartesaghi*
|
281
|
-
|
282
|
-
* Fixes multiple `attach` calls within transaction not uploading files correctly.
|
283
|
-
|
284
|
-
In the following example, the code failed to upload all but the last file to the configured service.
|
285
|
-
```ruby
|
286
|
-
ActiveRecord::Base.transaction do
|
287
|
-
user.attachments.attach({
|
288
|
-
content_type: "text/plain",
|
289
|
-
filename: "dummy.txt",
|
290
|
-
io: ::StringIO.new("dummy"),
|
291
|
-
})
|
292
|
-
user.attachments.attach({
|
293
|
-
content_type: "text/plain",
|
294
|
-
filename: "dummy2.txt",
|
295
|
-
io: ::StringIO.new("dummy2"),
|
296
|
-
})
|
297
|
-
end
|
298
|
-
|
299
|
-
assert_equal 2, user.attachments.count
|
300
|
-
assert user.attachments.first.service.exist?(user.attachments.first.key) # Fails
|
301
|
-
```
|
302
|
-
|
303
|
-
This was addressed by keeping track of the subchanges pending upload, and uploading them
|
304
|
-
once the transaction is committed.
|
305
|
-
|
306
|
-
Fixes #41661
|
307
|
-
|
308
|
-
*Santiago Bartesaghi*, *Bruno Vezoli*, *Juan Roig*, *Abhay Nikam*
|
309
|
-
|
310
|
-
* Raise an exception if `config.active_storage.service` is not set.
|
311
|
-
|
312
|
-
If Active Storage is configured and `config.active_storage.service` is not
|
313
|
-
set in the respective environment's configuration file, then an exception
|
314
|
-
is raised with a meaningful message when attempting to use Active Storage.
|
315
|
-
|
316
|
-
*Ghouse Mohamed*
|
317
|
-
|
318
|
-
* Fixes proxy downloads of files over 5mb
|
319
|
-
|
320
|
-
Previously, trying to view and/or download files larger than 5mb stored in
|
321
|
-
services like S3 via proxy mode could return corrupted files at around
|
322
|
-
5.2mb or cause random halts in the download. Now,
|
323
|
-
`ActiveStorage::Blobs::ProxyController` correctly handles streaming these
|
324
|
-
larger files from the service to the client without any issues.
|
325
|
-
|
326
|
-
Fixes #44679
|
327
|
-
|
328
|
-
*Felipe Raul*
|
329
|
-
|
330
|
-
* Saving attachment(s) to a record returns the blob/blobs object
|
331
|
-
|
332
|
-
Previously, saving attachments did not return the blob/blobs that
|
333
|
-
were attached. Now, saving attachments to a record with `#attach`
|
334
|
-
method returns the blob or array of blobs that were attached to
|
335
|
-
the record. If it fails to save the attachment(s), then it returns
|
336
|
-
`false`.
|
337
|
-
|
338
|
-
*Ghouse Mohamed*
|
339
|
-
|
340
|
-
* Don't stream responses in redirect mode
|
341
|
-
|
342
|
-
Previously, both redirect mode and proxy mode streamed their
|
343
|
-
responses which caused a new thread to be created, and could end
|
344
|
-
up leaking connections in the connection pool. But since redirect
|
345
|
-
mode doesn't actually send any data, it doesn't need to be
|
346
|
-
streamed.
|
347
|
-
|
348
|
-
*Luke Lau*
|
349
|
-
|
350
|
-
* Safe for direct upload on Libraries or Frameworks
|
351
|
-
|
352
|
-
Enable the use of custom headers during direct uploads, which allows for
|
353
|
-
the inclusion of Authorization bearer tokens or other forms of authorization
|
354
|
-
tokens through headers.
|
355
|
-
|
356
|
-
*Radamés Roriz*
|
101
|
+
*Yogesh Khater*
|
357
102
|
|
358
|
-
Please check [7-
|
103
|
+
Please check [7-1-stable](https://github.com/rails/rails/blob/7-1-stable/activestorage/CHANGELOG.md) for previous changes.
|
@@ -22,13 +22,13 @@ class ActiveStorage::Attachment < ActiveStorage::Record
|
|
22
22
|
# :method:
|
23
23
|
#
|
24
24
|
# Returns the associated record.
|
25
|
-
belongs_to :record, polymorphic: true, touch:
|
25
|
+
belongs_to :record, polymorphic: true, touch: ActiveStorage.touch_attachment_records
|
26
26
|
|
27
27
|
##
|
28
28
|
# :method:
|
29
29
|
#
|
30
30
|
# Returns the associated ActiveStorage::Blob.
|
31
|
-
belongs_to :blob, class_name: "ActiveStorage::Blob", autosave: true
|
31
|
+
belongs_to :blob, class_name: "ActiveStorage::Blob", autosave: true, inverse_of: :attachments
|
32
32
|
|
33
33
|
delegate_missing_to :blob
|
34
34
|
delegate :signed_id, to: :blob
|
@@ -138,7 +138,7 @@ class ActiveStorage::Attachment < ActiveStorage::Record
|
|
138
138
|
end
|
139
139
|
}
|
140
140
|
|
141
|
-
if blob.preview_image_needed_before_processing_variants?
|
141
|
+
if blob.preview_image_needed_before_processing_variants? && preprocessed_variations.any?
|
142
142
|
blob.create_preview_image_later(preprocessed_variations)
|
143
143
|
else
|
144
144
|
preprocessed_variations.each do |transformations|
|
@@ -156,7 +156,7 @@ class ActiveStorage::Attachment < ActiveStorage::Record
|
|
156
156
|
end
|
157
157
|
|
158
158
|
def named_variants
|
159
|
-
record.attachment_reflections[name]&.named_variants
|
159
|
+
record.attachment_reflections[name]&.named_variants || {}
|
160
160
|
end
|
161
161
|
|
162
162
|
def transformations_by_name(transformations)
|
@@ -17,11 +17,6 @@
|
|
17
17
|
# update a blob's metadata on a subsequent pass, but you should not update the key or change the uploaded file.
|
18
18
|
# If you need to create a derivative or otherwise change the blob, simply create a new blob and purge the old one.
|
19
19
|
class ActiveStorage::Blob < ActiveStorage::Record
|
20
|
-
include Analyzable
|
21
|
-
include Identifiable
|
22
|
-
include Representable
|
23
|
-
include Servable
|
24
|
-
|
25
20
|
MINIMUM_TOKEN_LENGTH = 28
|
26
21
|
|
27
22
|
has_secure_token :key, length: MINIMUM_TOKEN_LENGTH
|
@@ -46,7 +41,7 @@ class ActiveStorage::Blob < ActiveStorage::Record
|
|
46
41
|
self.service_name ||= self.class.service&.name
|
47
42
|
end
|
48
43
|
|
49
|
-
after_update :
|
44
|
+
after_update :touch_attachments
|
50
45
|
|
51
46
|
after_update_commit :update_service_metadata, if: -> { content_type_previously_changed? || metadata_previously_changed? }
|
52
47
|
|
@@ -147,18 +142,39 @@ class ActiveStorage::Blob < ActiveStorage::Record
|
|
147
142
|
end
|
148
143
|
|
149
144
|
# Concatenate multiple blobs into a single "composed" blob.
|
150
|
-
def compose(blobs, filename:, content_type: nil, metadata: nil)
|
145
|
+
def compose(blobs, key: nil, filename:, content_type: nil, metadata: nil)
|
151
146
|
raise ActiveRecord::RecordNotSaved, "All blobs must be persisted." if blobs.any?(&:new_record?)
|
152
147
|
|
153
148
|
content_type ||= blobs.pluck(:content_type).compact.first
|
154
149
|
|
155
|
-
new(filename: filename, content_type: content_type, metadata: metadata, byte_size: blobs.sum(&:byte_size)).tap do |combined_blob|
|
150
|
+
new(key: key, filename: filename, content_type: content_type, metadata: metadata, byte_size: blobs.sum(&:byte_size)).tap do |combined_blob|
|
156
151
|
combined_blob.compose(blobs.pluck(:key))
|
157
152
|
combined_blob.save!
|
158
153
|
end
|
159
154
|
end
|
155
|
+
|
156
|
+
def validate_service_configuration(service_name, model_class, association_name) # :nodoc:
|
157
|
+
if service_name
|
158
|
+
services.fetch(service_name) do
|
159
|
+
raise ArgumentError, "Cannot configure service #{service_name.inspect} for #{model_class}##{association_name}"
|
160
|
+
end
|
161
|
+
else
|
162
|
+
validate_global_service_configuration
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def validate_global_service_configuration # :nodoc:
|
167
|
+
if connected? && table_exists? && Rails.configuration.active_storage.service.nil?
|
168
|
+
raise RuntimeError, "Missing Active Storage service name. Specify Active Storage service name for config.active_storage.service in config/environments/#{Rails.env}.rb"
|
169
|
+
end
|
170
|
+
end
|
160
171
|
end
|
161
172
|
|
173
|
+
include Analyzable
|
174
|
+
include Identifiable
|
175
|
+
include Representable
|
176
|
+
include Servable
|
177
|
+
|
162
178
|
# Returns a signed ID for this blob that's suitable for reference on the client-side without fear of tampering.
|
163
179
|
def signed_id(purpose: :blob_id, expires_in: nil, expires_at: nil)
|
164
180
|
super
|
@@ -334,8 +350,9 @@ class ActiveStorage::Blob < ActiveStorage::Record
|
|
334
350
|
raise ArgumentError, "io must be rewindable" unless io.respond_to?(:rewind)
|
335
351
|
|
336
352
|
OpenSSL::Digest::MD5.new.tap do |checksum|
|
337
|
-
|
338
|
-
|
353
|
+
read_buffer = "".b
|
354
|
+
while io.read(5.megabytes, read_buffer)
|
355
|
+
checksum << read_buffer
|
339
356
|
end
|
340
357
|
|
341
358
|
io.rewind
|
@@ -360,8 +377,14 @@ class ActiveStorage::Blob < ActiveStorage::Record
|
|
360
377
|
end
|
361
378
|
end
|
362
379
|
|
363
|
-
def
|
364
|
-
attachments.
|
380
|
+
def touch_attachments
|
381
|
+
attachments.then do |relation|
|
382
|
+
if ActiveStorage.touch_attachment_records
|
383
|
+
relation.includes(:record)
|
384
|
+
else
|
385
|
+
relation
|
386
|
+
end
|
387
|
+
end.each do |attachment|
|
365
388
|
attachment.touch
|
366
389
|
end
|
367
390
|
end
|
@@ -35,7 +35,7 @@ class ActiveStorage::Preview
|
|
35
35
|
|
36
36
|
class UnprocessedError < StandardError; end
|
37
37
|
|
38
|
-
delegate :filename, :content_type, to: :
|
38
|
+
delegate :filename, :content_type, to: :presentation
|
39
39
|
|
40
40
|
attr_reader :blob, :variation
|
41
41
|
|
@@ -51,7 +51,7 @@ class ActiveStorage::Preview
|
|
51
51
|
# image is stored with the blob, it is only generated once.
|
52
52
|
def processed
|
53
53
|
process unless processed?
|
54
|
-
variant.processed
|
54
|
+
variant.processed if variant?
|
55
55
|
self
|
56
56
|
end
|
57
57
|
|
@@ -67,7 +67,7 @@ class ActiveStorage::Preview
|
|
67
67
|
# a stable URL that redirects to the URL returned by this method.
|
68
68
|
def url(**options)
|
69
69
|
if processed?
|
70
|
-
|
70
|
+
presentation.url(**options)
|
71
71
|
else
|
72
72
|
raise UnprocessedError
|
73
73
|
end
|
@@ -76,7 +76,7 @@ class ActiveStorage::Preview
|
|
76
76
|
# Returns a combination key of the blob and the variation that together identifies a specific variant.
|
77
77
|
def key
|
78
78
|
if processed?
|
79
|
-
|
79
|
+
presentation.key
|
80
80
|
else
|
81
81
|
raise UnprocessedError
|
82
82
|
end
|
@@ -89,7 +89,7 @@ class ActiveStorage::Preview
|
|
89
89
|
# if the preview has not been processed yet.
|
90
90
|
def download(&block)
|
91
91
|
if processed?
|
92
|
-
|
92
|
+
presentation.download(&block)
|
93
93
|
else
|
94
94
|
raise UnprocessedError
|
95
95
|
end
|
@@ -109,7 +109,15 @@ class ActiveStorage::Preview
|
|
109
109
|
end
|
110
110
|
|
111
111
|
def variant
|
112
|
-
image.variant(variation)
|
112
|
+
image.variant(variation)
|
113
|
+
end
|
114
|
+
|
115
|
+
def variant?
|
116
|
+
variation.transformations.present?
|
117
|
+
end
|
118
|
+
|
119
|
+
def presentation
|
120
|
+
variant? ? variant.processed : image
|
113
121
|
end
|
114
122
|
|
115
123
|
|
@@ -51,6 +51,6 @@ class CreateActiveStorageTables < ActiveRecord::Migration[7.0]
|
|
51
51
|
setting = config.options[config.orm][:primary_key_type]
|
52
52
|
primary_key_type = setting || :primary_key
|
53
53
|
foreign_key_type = setting || :bigint
|
54
|
-
[primary_key_type, foreign_key_type]
|
54
|
+
[ primary_key_type, foreign_key_type ]
|
55
55
|
end
|
56
56
|
end
|
@@ -19,13 +19,16 @@ module ActiveStorage
|
|
19
19
|
|
20
20
|
download_blob_to_tempfile do |file|
|
21
21
|
image = instrument("vips") do
|
22
|
+
# ruby-vips will raise Vips::Error if it can't find an appropriate loader for the file
|
22
23
|
::Vips::Image.new_from_file(file.path, access: :sequential)
|
24
|
+
rescue ::Vips::Error
|
25
|
+
logger.info "Skipping image analysis because Vips doesn't support the file"
|
26
|
+
nil
|
23
27
|
end
|
24
28
|
|
25
|
-
if
|
29
|
+
if image
|
26
30
|
yield image
|
27
31
|
else
|
28
|
-
logger.info "Skipping image analysis because Vips doesn't support the file"
|
29
32
|
{}
|
30
33
|
end
|
31
34
|
rescue ::Vips::Error => error
|
@@ -40,12 +43,5 @@ module ActiveStorage
|
|
40
43
|
rescue ::Vips::Error
|
41
44
|
false
|
42
45
|
end
|
43
|
-
|
44
|
-
def valid_image?(image)
|
45
|
-
image.avg
|
46
|
-
true
|
47
|
-
rescue ::Vips::Error
|
48
|
-
false
|
49
|
-
end
|
50
46
|
end
|
51
47
|
end
|
@@ -55,11 +55,15 @@ module ActiveStorage
|
|
55
55
|
def angle
|
56
56
|
if tags["rotate"]
|
57
57
|
Integer(tags["rotate"])
|
58
|
-
elsif
|
59
|
-
Integer(
|
58
|
+
elsif display_matrix && display_matrix["rotation"]
|
59
|
+
Integer(display_matrix["rotation"])
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
63
|
+
def display_matrix
|
64
|
+
side_data.detect { |data| data["side_data_type"] == "Display Matrix" }
|
65
|
+
end
|
66
|
+
|
63
67
|
def display_aspect_ratio
|
64
68
|
if descriptor = video_stream["display_aspect_ratio"]
|
65
69
|
if terms = descriptor.split(":", 2)
|
@@ -118,7 +118,12 @@ module ActiveStorage
|
|
118
118
|
end
|
119
119
|
|
120
120
|
def attachment_service_name
|
121
|
-
record.attachment_reflections[name].options[:service_name]
|
121
|
+
service_name = record.attachment_reflections[name].options[:service_name]
|
122
|
+
if service_name.is_a?(Proc)
|
123
|
+
service_name = service_name.call(record)
|
124
|
+
ActiveStorage::Blob.validate_service_configuration(service_name, record.class, name)
|
125
|
+
end
|
126
|
+
service_name
|
122
127
|
end
|
123
128
|
end
|
124
129
|
end
|
@@ -4,7 +4,11 @@ module ActiveStorage
|
|
4
4
|
class Attached::Changes::CreateOneOfMany < Attached::Changes::CreateOne # :nodoc:
|
5
5
|
private
|
6
6
|
def find_attachment
|
7
|
-
|
7
|
+
if blob.persisted?
|
8
|
+
record.public_send("#{name}_attachments").detect { |attachment| attachment.blob_id == blob.id }
|
9
|
+
else
|
10
|
+
blob.attachments.find { |attachment| attachment.record == record }
|
11
|
+
end
|
8
12
|
end
|
9
13
|
end
|
10
14
|
end
|
@@ -80,12 +80,18 @@ module ActiveStorage
|
|
80
80
|
# +purge+ instead.
|
81
81
|
#
|
82
82
|
# If you need the attachment to use a service which differs from the globally configured one,
|
83
|
-
# pass the +:service+ option. For
|
83
|
+
# pass the +:service+ option. For example:
|
84
84
|
#
|
85
85
|
# class User < ActiveRecord::Base
|
86
86
|
# has_one_attached :avatar, service: :s3
|
87
87
|
# end
|
88
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
|
+
#
|
89
95
|
# If you need to enable +strict_loading+ to prevent lazy loading of attachment,
|
90
96
|
# pass the +:strict_loading+ option. You can do:
|
91
97
|
#
|
@@ -93,8 +99,12 @@ module ActiveStorage
|
|
93
99
|
# has_one_attached :avatar, strict_loading: true
|
94
100
|
# end
|
95
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.
|
96
106
|
def has_one_attached(name, dependent: :purge_later, service: nil, strict_loading: false)
|
97
|
-
validate_service_configuration(
|
107
|
+
ActiveStorage::Blob.validate_service_configuration(service, self, name) unless service.is_a?(Proc)
|
98
108
|
|
99
109
|
generated_association_methods.class_eval <<-CODE, __FILE__, __LINE__ + 1
|
100
110
|
# frozen_string_literal: true
|
@@ -170,12 +180,18 @@ module ActiveStorage
|
|
170
180
|
# +purge+ instead.
|
171
181
|
#
|
172
182
|
# If you need the attachment to use a service which differs from the globally configured one,
|
173
|
-
# pass the +:service+ option. For
|
183
|
+
# pass the +:service+ option. For example:
|
174
184
|
#
|
175
185
|
# class Gallery < ActiveRecord::Base
|
176
186
|
# has_many_attached :photos, service: :s3
|
177
187
|
# end
|
178
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
|
+
#
|
179
195
|
# If you need to enable +strict_loading+ to prevent lazy loading of attachments,
|
180
196
|
# pass the +:strict_loading+ option. You can do:
|
181
197
|
#
|
@@ -183,8 +199,12 @@ module ActiveStorage
|
|
183
199
|
# has_many_attached :photos, strict_loading: true
|
184
200
|
# end
|
185
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.
|
186
206
|
def has_many_attached(name, dependent: :purge_later, service: nil, strict_loading: false)
|
187
|
-
validate_service_configuration(
|
207
|
+
ActiveStorage::Blob.validate_service_configuration(service, self, name) unless service.is_a?(Proc)
|
188
208
|
|
189
209
|
generated_association_methods.class_eval <<-CODE, __FILE__, __LINE__ + 1
|
190
210
|
# frozen_string_literal: true
|
@@ -233,23 +253,6 @@ module ActiveStorage
|
|
233
253
|
yield reflection if block_given?
|
234
254
|
ActiveRecord::Reflection.add_attachment_reflection(self, name, reflection)
|
235
255
|
end
|
236
|
-
|
237
|
-
private
|
238
|
-
def validate_service_configuration(association_name, service)
|
239
|
-
if service.present?
|
240
|
-
ActiveStorage::Blob.services.fetch(service) do
|
241
|
-
raise ArgumentError, "Cannot configure service :#{service} for #{name}##{association_name}"
|
242
|
-
end
|
243
|
-
else
|
244
|
-
validate_global_service_configuration
|
245
|
-
end
|
246
|
-
end
|
247
|
-
|
248
|
-
def validate_global_service_configuration
|
249
|
-
if connected? && ActiveStorage::Blob.table_exists? && Rails.configuration.active_storage.service.nil?
|
250
|
-
raise RuntimeError, "Missing Active Storage service name. Specify Active Storage service name for config.active_storage.service in config/environments/#{Rails.env}.rb"
|
251
|
-
end
|
252
|
-
end
|
253
256
|
end
|
254
257
|
|
255
258
|
def attachment_changes # :nodoc:
|
@@ -65,6 +65,8 @@ module ActiveStorage
|
|
65
65
|
)
|
66
66
|
|
67
67
|
config.active_storage.content_types_allowed_inline = %w(
|
68
|
+
image/webp
|
69
|
+
image/avif
|
68
70
|
image/png
|
69
71
|
image/gif
|
70
72
|
image/jpeg
|
@@ -110,20 +112,12 @@ module ActiveStorage
|
|
110
112
|
ActiveStorage.variable_content_types = app.config.active_storage.variable_content_types || []
|
111
113
|
ActiveStorage.web_image_content_types = app.config.active_storage.web_image_content_types || []
|
112
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
|
113
116
|
ActiveStorage.service_urls_expire_in = app.config.active_storage.service_urls_expire_in || 5.minutes
|
114
117
|
ActiveStorage.urls_expire_in = app.config.active_storage.urls_expire_in
|
115
118
|
ActiveStorage.content_types_allowed_inline = app.config.active_storage.content_types_allowed_inline || []
|
116
119
|
ActiveStorage.binary_content_type = app.config.active_storage.binary_content_type || "application/octet-stream"
|
117
120
|
ActiveStorage.video_preview_arguments = app.config.active_storage.video_preview_arguments || "-y -vframes 1 -f image2"
|
118
|
-
|
119
|
-
unless app.config.active_storage.silence_invalid_content_types_warning.nil?
|
120
|
-
ActiveStorage.silence_invalid_content_types_warning = app.config.active_storage.silence_invalid_content_types_warning
|
121
|
-
end
|
122
|
-
|
123
|
-
unless app.config.active_storage.replace_on_assign_to_many.nil?
|
124
|
-
ActiveStorage.replace_on_assign_to_many = app.config.active_storage.replace_on_assign_to_many
|
125
|
-
end
|
126
|
-
|
127
121
|
ActiveStorage.track_variants = app.config.active_storage.track_variants || false
|
128
122
|
end
|
129
123
|
end
|
@@ -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
|
@@ -5,7 +5,7 @@ begin
|
|
5
5
|
rescue LoadError
|
6
6
|
raise LoadError, <<~ERROR.squish
|
7
7
|
Generating image variants require the image_processing gem.
|
8
|
-
Please add `gem
|
8
|
+
Please add `gem "image_processing", "~> 1.2"` to your Gemfile.
|
9
9
|
ERROR
|
10
10
|
end
|
11
11
|
|
data/lib/active_storage.rb
CHANGED
@@ -354,6 +354,7 @@ module ActiveStorage
|
|
354
354
|
mattr_accessor :unsupported_image_processing_arguments
|
355
355
|
|
356
356
|
mattr_accessor :service_urls_expire_in, default: 5.minutes
|
357
|
+
mattr_accessor :touch_attachment_records, default: true
|
357
358
|
mattr_accessor :urls_expire_in
|
358
359
|
|
359
360
|
mattr_accessor :routes_prefix, default: "/rails/active_storage"
|
@@ -364,22 +365,6 @@ module ActiveStorage
|
|
364
365
|
|
365
366
|
mattr_accessor :video_preview_arguments, default: "-y -vframes 1 -f image2"
|
366
367
|
|
367
|
-
def self.replace_on_assign_to_many
|
368
|
-
ActiveStorage.deprecator.warn("config.active_storage.replace_on_assign_to_many is deprecated and has no effect.")
|
369
|
-
end
|
370
|
-
|
371
|
-
def self.replace_on_assign_to_many=(value)
|
372
|
-
ActiveStorage.deprecator.warn("config.active_storage.replace_on_assign_to_many is deprecated and has no effect.")
|
373
|
-
end
|
374
|
-
|
375
|
-
def self.silence_invalid_content_types_warning
|
376
|
-
ActiveStorage.deprecator.warn("config.active_storage.silence_invalid_content_types_warning is deprecated and has no effect.")
|
377
|
-
end
|
378
|
-
|
379
|
-
def self.silence_invalid_content_types_warning=(value)
|
380
|
-
ActiveStorage.deprecator.warn("config.active_storage.silence_invalid_content_types_warning is deprecated and has no effect.")
|
381
|
-
end
|
382
|
-
|
383
368
|
module Transformers
|
384
369
|
extend ActiveSupport::Autoload
|
385
370
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activestorage
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 7.
|
4
|
+
version: 7.2.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Heinemeier Hansson
|
@@ -16,56 +16,56 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - '='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 7.
|
19
|
+
version: 7.2.2.1
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - '='
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 7.
|
26
|
+
version: 7.2.2.1
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: actionpack
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - '='
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 7.
|
33
|
+
version: 7.2.2.1
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - '='
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 7.
|
40
|
+
version: 7.2.2.1
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: activejob
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - '='
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: 7.
|
47
|
+
version: 7.2.2.1
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - '='
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: 7.
|
54
|
+
version: 7.2.2.1
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: activerecord
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - '='
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: 7.
|
61
|
+
version: 7.2.2.1
|
62
62
|
type: :runtime
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - '='
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: 7.
|
68
|
+
version: 7.2.2.1
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: marcel
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -190,10 +190,10 @@ licenses:
|
|
190
190
|
- MIT
|
191
191
|
metadata:
|
192
192
|
bug_tracker_uri: https://github.com/rails/rails/issues
|
193
|
-
changelog_uri: https://github.com/rails/rails/blob/v7.
|
194
|
-
documentation_uri: https://api.rubyonrails.org/v7.
|
193
|
+
changelog_uri: https://github.com/rails/rails/blob/v7.2.2.1/activestorage/CHANGELOG.md
|
194
|
+
documentation_uri: https://api.rubyonrails.org/v7.2.2.1/
|
195
195
|
mailing_list_uri: https://discuss.rubyonrails.org/c/rubyonrails-talk
|
196
|
-
source_code_uri: https://github.com/rails/rails/tree/v7.
|
196
|
+
source_code_uri: https://github.com/rails/rails/tree/v7.2.2.1/activestorage
|
197
197
|
rubygems_mfa_required: 'true'
|
198
198
|
post_install_message:
|
199
199
|
rdoc_options: []
|
@@ -203,7 +203,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
203
203
|
requirements:
|
204
204
|
- - ">="
|
205
205
|
- !ruby/object:Gem::Version
|
206
|
-
version:
|
206
|
+
version: 3.1.0
|
207
207
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
208
208
|
requirements:
|
209
209
|
- - ">="
|