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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 206c165931991ed4701825d28d46e636a5a9aa38ff25d196f14906246d95c557
4
- data.tar.gz: de61985ef1a441eeb98646f9f0231693ee3142f3d9c9793fd7e38678e08686c7
3
+ metadata.gz: 19f4fa25c348a39b38b18a049dd123c5a0c6f80d70e05cdfc4790c7e0dbf96d1
4
+ data.tar.gz: 48ba490e74129a1495ed0b3249730bfeba7b12f916e787849e7cfa4f81235bf9
5
5
  SHA512:
6
- metadata.gz: fed89deed587674a3ea944cc1a02f8bb09c698409cc724cc1e127cf704b7ec777f45682eb88b6f455b251ceb576be00f0504c65086b0727af65cd70f1648bf0e
7
- data.tar.gz: 678cfe23e61e1a46039cbfedb20777103203e1fdba5455a47f49ba8e21a18d2887882d1eb85d7151af4424e04da4334eee3b0b7de198dedbde73597f378899ad
6
+ metadata.gz: 6656a5f10b464e63d86f0e4fc60984735e522d56789f93ce4f0d6ec4684b0b7e6a449f14af01a92e5929b1a4854f283b0bf89b37fe67ecb5d8cc207430b81c71
7
+ data.tar.gz: a8fe146a25f52b241de32978f344a2303ad5221f05306a57776337194ba67aa2691c715790131056dec44dfe21cb26b7df1fe33fef5d09efba3ff5f226b83e58
data/CHANGELOG.md CHANGED
@@ -1,51 +1,50 @@
1
- ## Rails 7.1.5.1 (December 10, 2024) ##
1
+ ## Rails 7.2.2.1 (December 10, 2024) ##
2
2
 
3
3
  * No changes.
4
4
 
5
5
 
6
- ## Rails 7.1.5 (October 30, 2024) ##
6
+ ## Rails 7.2.2 (October 30, 2024) ##
7
7
 
8
8
  * No changes.
9
9
 
10
10
 
11
- ## Rails 7.1.4.2 (October 23, 2024) ##
11
+ ## Rails 7.2.1.2 (October 23, 2024) ##
12
12
 
13
13
  * No changes.
14
14
 
15
15
 
16
- ## Rails 7.1.4.1 (October 15, 2024) ##
16
+ ## Rails 7.2.1.1 (October 15, 2024) ##
17
17
 
18
18
  * No changes.
19
19
 
20
20
 
21
- ## Rails 7.1.4 (August 22, 2024) ##
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.1.3.3 (May 16, 2024) ##
26
+ ## Rails 7.2.0 (August 09, 2024) ##
34
27
 
35
- * No changes.
28
+ * Remove deprecated `config.active_storage.silence_invalid_content_types_warning`.
36
29
 
30
+ *Rafael Mendonça França*
37
31
 
38
- ## Rails 7.1.3.2 (February 21, 2024) ##
32
+ * Remove deprecated `config.active_storage.replace_on_assign_to_many`.
39
33
 
40
- * No changes.
34
+ *Rafael Mendonça França*
41
35
 
36
+ * Add support for custom `key` in `ActiveStorage::Blob#compose`.
42
37
 
43
- ## Rails 7.1.3.1 (February 21, 2024) ##
38
+ *Elvin Efendiev*
44
39
 
45
- * No changes.
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
- ## Rails 7.1.3 (January 16, 2024) ##
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
- ## Rails 7.1.2 (November 10, 2023) ##
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-0-stable](https://github.com/rails/rails/blob/7-0-stable/activestorage/CHANGELOG.md) for previous changes.
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: true
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 :touch_attachment_records
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
- while chunk = io.read(5.megabytes)
338
- checksum << chunk
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 touch_attachment_records
364
- attachments.includes(:record).each do |attachment|
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
@@ -69,10 +69,6 @@ class ActiveStorage::Filename
69
69
  to_s
70
70
  end
71
71
 
72
- def to_json
73
- to_s
74
- end
75
-
76
72
  def <=>(other)
77
73
  to_s.downcase <=> other.to_s.downcase
78
74
  end
@@ -35,7 +35,7 @@ class ActiveStorage::Preview
35
35
 
36
36
  class UnprocessedError < StandardError; end
37
37
 
38
- delegate :filename, :content_type, to: :variant
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
- variant.url(**options)
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
- variant.key
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
- variant.download(&block)
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).processed
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 valid_image?(image)
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 side_data && side_data[0] && side_data[0]["rotation"]
59
- Integer(side_data[0]["rotation"])
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
- record.public_send("#{name}_attachments").detect { |attachment| attachment.blob_id == blob.id }
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 instance:
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(name, service)
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 instance:
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(name, service)
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
@@ -8,8 +8,8 @@ module ActiveStorage
8
8
 
9
9
  module VERSION
10
10
  MAJOR = 7
11
- MINOR = 1
12
- TINY = 5
11
+ MINOR = 2
12
+ TINY = 2
13
13
  PRE = "1"
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
@@ -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 == "application/pdf" && mutool_exists?
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 if defined?(@mutool_exists) && !@mutool_exists.nil?
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 == "application/pdf" && pdftoppm_exists?
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 if defined?(@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
@@ -10,7 +10,7 @@ module ActiveStorage
10
10
  end
11
11
 
12
12
  def ffmpeg_exists?
13
- return @ffmpeg_exists if defined?(@ffmpeg_exists)
13
+ return @ffmpeg_exists unless @ffmpeg_exists.nil?
14
14
 
15
15
  @ffmpeg_exists = system(ffmpeg_path, "-version", out: File::NULL, err: File::NULL)
16
16
  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 'image_processing', '~> 1.2'` to your Gemfile.
8
+ Please add `gem "image_processing", "~> 1.2"` to your Gemfile.
9
9
  ERROR
10
10
  end
11
11
 
@@ -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.1.5.1
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.1.5.1
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.1.5.1
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.1.5.1
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.1.5.1
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.1.5.1
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.1.5.1
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.1.5.1
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.1.5.1
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.1.5.1/activestorage/CHANGELOG.md
194
- documentation_uri: https://api.rubyonrails.org/v7.1.5.1/
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.1.5.1/activestorage
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: 2.7.0
206
+ version: 3.1.0
207
207
  required_rubygems_version: !ruby/object:Gem::Requirement
208
208
  requirements:
209
209
  - - ">="