activestorage 7.1.0 → 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 +51 -200
- data/app/assets/javascripts/activestorage.esm.js +3 -3
- data/app/assets/javascripts/activestorage.js +3 -3
- data/app/controllers/active_storage/representations/proxy_controller.rb +1 -1
- data/app/javascript/activestorage/ujs.js +3 -3
- data/app/jobs/active_storage/preview_image_job.rb +16 -0
- data/app/jobs/active_storage/transform_job.rb +2 -2
- data/app/models/active_storage/attachment.rb +19 -8
- data/app/models/active_storage/blob/representable.rb +9 -1
- data/app/models/active_storage/blob/servable.rb +22 -0
- data/app/models/active_storage/blob.rb +40 -33
- data/app/models/active_storage/filename.rb +0 -4
- data/app/models/active_storage/preview.rb +18 -5
- data/app/models/active_storage/variant.rb +2 -0
- data/app/models/active_storage/variant_record.rb +0 -2
- data/app/models/active_storage/variant_with_record.rb +2 -0
- 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 +40 -27
- data/lib/active_storage/engine.rb +3 -9
- data/lib/active_storage/fixture_set.rb +5 -1
- data/lib/active_storage/gem_version.rb +3 -3
- 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 +2 -17
- metadata +20 -18
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,252 +1,103 @@
|
|
1
|
-
## Rails 7.1
|
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
|
-
*
|
14
|
-
|
15
|
-
```ruby
|
16
|
-
rails_blob_path(user.avatar, disposition: "attachment", expires_at: 30.minutes.from_now)
|
17
|
-
<%= image_tag rails_blob_path(user.avatar.variant(resize: "100x100"), expires_at: 30.minutes.from_now) %>
|
18
|
-
```
|
19
|
-
|
20
|
-
*Aki*
|
21
|
-
|
22
|
-
* Allow attaching File and Pathname when assigning attributes, e.g.
|
23
|
-
|
24
|
-
```ruby
|
25
|
-
User.create!(avatar: File.open("image.jpg"))
|
26
|
-
User.create!(avatar: file_fixture("image.jpg"))
|
27
|
-
```
|
28
|
-
|
29
|
-
*Dorian Marié*
|
30
|
-
|
31
|
-
|
32
|
-
## Rails 7.1.0.beta1 (September 13, 2023) ##
|
33
|
-
|
34
|
-
* Disables the session in `ActiveStorage::Blobs::ProxyController`
|
35
|
-
and `ActiveStorage::Representations::ProxyController`
|
36
|
-
in order to allow caching by default in some CDNs as CloudFlare
|
37
|
-
|
38
|
-
Fixes #44136
|
39
|
-
|
40
|
-
*Bruno Prieto*
|
41
|
-
|
42
|
-
* Add `tags` to `ActiveStorage::Analyzer::AudioAnalyzer` output
|
43
|
-
|
44
|
-
*Keaton Roux*
|
45
|
-
|
46
|
-
* Add an option to preprocess variants
|
47
|
-
|
48
|
-
ActiveStorage variants are processed on the fly when they are needed but
|
49
|
-
sometimes we're sure that they are accessed and want to processed them
|
50
|
-
upfront.
|
51
|
-
|
52
|
-
`preprocessed` option is added when declaring variants.
|
53
|
-
|
54
|
-
```
|
55
|
-
class User < ApplicationRecord
|
56
|
-
has_one_attached :avatar do |attachable|
|
57
|
-
attachable.variant :thumb, resize_to_limit: [100, 100], preprocessed: true
|
58
|
-
end
|
59
|
-
end
|
60
|
-
```
|
61
|
-
|
62
|
-
*Shouichi Kamiya*
|
63
|
-
|
64
|
-
* Fix variants not included when eager loading multiple records containing a single attachment
|
65
|
-
|
66
|
-
When using the `with_attached_#{name}` scope for a `has_one_attached` relation,
|
67
|
-
attachment variants were not eagerly loaded.
|
68
|
-
|
69
|
-
*Russell Porter*
|
70
|
-
|
71
|
-
* Allow an ActiveStorage attachment to be removed via a form post
|
72
|
-
|
73
|
-
Attachments can already be removed by updating the attachment to be nil such as:
|
74
|
-
```ruby
|
75
|
-
User.find(params[:id]).update!(avatar: nil)
|
76
|
-
```
|
77
|
-
|
78
|
-
However, a form cannot post a nil param, it can only post an empty string. But, posting an
|
79
|
-
empty string would result in an `ActiveSupport::MessageVerifier::InvalidSignature: mismatched digest`
|
80
|
-
error being raised, because it's being treated as a signed blob id.
|
81
|
-
|
82
|
-
Now, nil and an empty string are treated as a delete, which allows attachments to be removed via:
|
83
|
-
```ruby
|
84
|
-
User.find(params[:id]).update!(params.require(:user).permit(:avatar))
|
85
|
-
|
86
|
-
```
|
87
|
-
|
88
|
-
*Nate Matykiewicz*
|
89
|
-
|
90
|
-
* Remove mini_mime usage in favour of marcel.
|
91
|
-
|
92
|
-
We have two libraries that are have similar usage. This change removes
|
93
|
-
dependency on mini_mime and makes use of similar methods from marcel.
|
94
|
-
|
95
|
-
*Vipul A M*
|
96
|
-
|
97
|
-
* Allow destroying active storage variants
|
13
|
+
* No changes.
|
98
14
|
|
99
|
-
```ruby
|
100
|
-
User.first.avatar.variant(resize_to_limit: [100, 100]).destroy
|
101
|
-
```
|
102
15
|
|
103
|
-
|
16
|
+
## Rails 7.2.1.1 (October 15, 2024) ##
|
104
17
|
|
105
|
-
*
|
18
|
+
* No changes.
|
106
19
|
|
107
|
-
*Matija Čupić*
|
108
20
|
|
109
|
-
|
21
|
+
## Rails 7.2.1 (August 22, 2024) ##
|
110
22
|
|
111
|
-
|
112
|
-
|
113
|
-
* Remove deprecated behavior when assigning to a collection of attachments.
|
23
|
+
* No changes.
|
114
24
|
|
115
|
-
Instead of appending to the collection, the collection is now replaced.
|
116
25
|
|
117
|
-
|
26
|
+
## Rails 7.2.0 (August 09, 2024) ##
|
118
27
|
|
119
|
-
* Remove deprecated `
|
28
|
+
* Remove deprecated `config.active_storage.silence_invalid_content_types_warning`.
|
120
29
|
|
121
30
|
*Rafael Mendonça França*
|
122
31
|
|
123
|
-
* Remove deprecated
|
32
|
+
* Remove deprecated `config.active_storage.replace_on_assign_to_many`.
|
124
33
|
|
125
34
|
*Rafael Mendonça França*
|
126
35
|
|
127
|
-
* Add
|
128
|
-
|
129
|
-
A `preview` event is being instrumented in `ActiveStorage::Previewer`.
|
130
|
-
However it was not added inside ActiveStorage's LogSubscriber class.
|
131
|
-
|
132
|
-
This will allow to have logs for when a preview happens
|
133
|
-
in the same fashion as all other ActiveStorage events such as
|
134
|
-
`upload` and `download` inside `Rails.logger`.
|
135
|
-
|
136
|
-
*Chedli Bourguiba*
|
137
|
-
|
138
|
-
* Fix retrieving rotation value from FFmpeg on version 5.0+.
|
139
|
-
|
140
|
-
In FFmpeg version 5.0+ the rotation value has been removed from tags.
|
141
|
-
Instead the value can be found in side_data_list. Along with
|
142
|
-
this update it's possible to have values of -90, -270 to denote the video
|
143
|
-
has been rotated.
|
144
|
-
|
145
|
-
*Haroon Ahmed*
|
146
|
-
|
147
|
-
* Touch all corresponding model records after ActiveStorage::Blob is analyzed
|
148
|
-
|
149
|
-
This fixes a race condition where a record can be requested and have a cache entry built, before
|
150
|
-
the initial `analyze_later` completes, which will not be invalidated until something else
|
151
|
-
updates the record. This also invalidates cache entries when a blob is re-analyzed, which
|
152
|
-
is helpful if a bug is fixed in an analyzer or a new analyzer is added.
|
153
|
-
|
154
|
-
*Nate Matykiewicz*
|
36
|
+
* Add support for custom `key` in `ActiveStorage::Blob#compose`.
|
155
37
|
|
156
|
-
*
|
157
|
-
`representation` on an attachment.
|
38
|
+
*Elvin Efendiev*
|
158
39
|
|
159
|
-
|
160
|
-
|
161
|
-
has_one_attached :file do |attachable|
|
162
|
-
attachable.variant :thumb, resize_to_limit: [100, 100]
|
163
|
-
end
|
164
|
-
end
|
40
|
+
* Add `image/webp` to `config.active_storage.web_image_content_types` when `load_defaults "7.2"`
|
41
|
+
is set.
|
165
42
|
|
166
|
-
|
167
|
-
```
|
43
|
+
*Lewis Buckley*
|
168
44
|
|
169
|
-
|
45
|
+
* Fix JSON-encoding of `ActiveStorage::Filename` instances.
|
170
46
|
|
171
|
-
*
|
172
|
-
is persisted, unchanged, and saving it fails, in which case it returns `nil`.
|
47
|
+
*Jonathan del Strother*
|
173
48
|
|
174
|
-
|
49
|
+
* Fix N+1 query when fetching preview images for non-image assets.
|
175
50
|
|
176
|
-
*
|
51
|
+
*Aaron Patterson & Justin Searls*
|
177
52
|
|
178
|
-
|
179
|
-
|
180
|
-
ActiveRecord::Base.transaction do
|
181
|
-
user.attachments.attach({
|
182
|
-
content_type: "text/plain",
|
183
|
-
filename: "dummy.txt",
|
184
|
-
io: ::StringIO.new("dummy"),
|
185
|
-
})
|
186
|
-
user.attachments.attach({
|
187
|
-
content_type: "text/plain",
|
188
|
-
filename: "dummy2.txt",
|
189
|
-
io: ::StringIO.new("dummy2"),
|
190
|
-
})
|
191
|
-
end
|
53
|
+
* Fix all Active Storage database related models to respect
|
54
|
+
`ActiveRecord::Base.table_name_prefix` configuration.
|
192
55
|
|
193
|
-
|
194
|
-
assert user.attachments.first.service.exist?(user.attachments.first.key) # Fails
|
195
|
-
```
|
196
|
-
|
197
|
-
This was addressed by keeping track of the subchanges pending upload, and uploading them
|
198
|
-
once the transaction is committed.
|
56
|
+
*Chedli Bourguiba*
|
199
57
|
|
200
|
-
|
58
|
+
* Fix `ActiveStorage::Representations::ProxyController` not returning the proper
|
59
|
+
preview image variant for previewable files.
|
201
60
|
|
202
|
-
*
|
61
|
+
*Chedli Bourguiba*
|
203
62
|
|
204
|
-
*
|
63
|
+
* Fix `ActiveStorage::Representations::ProxyController` to proxy untracked
|
64
|
+
variants.
|
205
65
|
|
206
|
-
|
207
|
-
set in the respective environment's configuration file, then an exception
|
208
|
-
is raised with a meaningful message when attempting to use Active Storage.
|
66
|
+
*Chedli Bourguiba*
|
209
67
|
|
210
|
-
|
68
|
+
* When using the `preprocessed: true` option, avoid enqueuing transform jobs
|
69
|
+
for blobs that are not representable.
|
211
70
|
|
212
|
-
*
|
71
|
+
*Chedli Bourguiba*
|
213
72
|
|
214
|
-
|
215
|
-
services like S3 via proxy mode could return corrupted files at around
|
216
|
-
5.2mb or cause random halts in the download. Now,
|
217
|
-
`ActiveStorage::Blobs::ProxyController` correctly handles streaming these
|
218
|
-
larger files from the service to the client without any issues.
|
73
|
+
* Prevent `ActiveStorage::Blob#preview` to generate a variant if an empty variation is passed.
|
219
74
|
|
220
|
-
|
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.
|
221
77
|
|
222
|
-
*
|
78
|
+
*Chedli Bourguiba*
|
223
79
|
|
224
|
-
*
|
80
|
+
* Process preview image variant when calling `ActiveStorage::Preview#processed`.
|
225
81
|
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
`false`.
|
82
|
+
For example, `attached_pdf.preview(:thumb).processed` will now immediately
|
83
|
+
generate the full-sized preview image and the `:thumb` variant of it.
|
84
|
+
Previously, the `:thumb` variant would not be generated until a further call
|
85
|
+
to e.g. `processed.url`.
|
231
86
|
|
232
|
-
*
|
87
|
+
*Chedli Bourguiba* and *Jonathan Hefner*
|
233
88
|
|
234
|
-
*
|
89
|
+
* Prevent `ActiveRecord::StrictLoadingViolationError` when strict loading is
|
90
|
+
enabled and the variant of an Active Storage preview has already been
|
91
|
+
processed (for example, by calling `ActiveStorage::Preview#url`).
|
235
92
|
|
236
|
-
|
237
|
-
responses which caused a new thread to be created, and could end
|
238
|
-
up leaking connections in the connection pool. But since redirect
|
239
|
-
mode doesn't actually send any data, it doesn't need to be
|
240
|
-
streamed.
|
93
|
+
*Jonathan Hefner*
|
241
94
|
|
242
|
-
|
95
|
+
* Fix `preprocessed: true` option for named variants of previewable files.
|
243
96
|
|
244
|
-
*
|
97
|
+
*Nico Wenterodt*
|
245
98
|
|
246
|
-
|
247
|
-
the inclusion of Authorization bearer tokens or other forms of authorization
|
248
|
-
tokens through headers.
|
99
|
+
* Allow accepting `service` as a proc as well in `has_one_attached` and `has_many_attached`.
|
249
100
|
|
250
|
-
*
|
101
|
+
*Yogesh Khater*
|
251
102
|
|
252
|
-
Please check [7-
|
103
|
+
Please check [7-1-stable](https://github.com/rails/rails/blob/7-1-stable/activestorage/CHANGELOG.md) for previous changes.
|
@@ -771,9 +771,9 @@ function start() {
|
|
771
771
|
}
|
772
772
|
|
773
773
|
function didClick(event) {
|
774
|
-
const
|
775
|
-
if (
|
776
|
-
submitButtonsByForm.set(
|
774
|
+
const button = event.target.closest("button, input");
|
775
|
+
if (button && button.type === "submit" && button.form) {
|
776
|
+
submitButtonsByForm.set(button.form, button);
|
777
777
|
}
|
778
778
|
}
|
779
779
|
|
@@ -754,9 +754,9 @@
|
|
754
754
|
}
|
755
755
|
}
|
756
756
|
function didClick(event) {
|
757
|
-
const
|
758
|
-
if (
|
759
|
-
submitButtonsByForm.set(
|
757
|
+
const button = event.target.closest("button, input");
|
758
|
+
if (button && button.type === "submit" && button.form) {
|
759
|
+
submitButtonsByForm.set(button.form, button);
|
760
760
|
}
|
761
761
|
}
|
762
762
|
function didSubmitForm(event) {
|
@@ -12,7 +12,7 @@ class ActiveStorage::Representations::ProxyController < ActiveStorage::Represent
|
|
12
12
|
|
13
13
|
def show
|
14
14
|
http_cache_forever public: true do
|
15
|
-
send_blob_stream @representation
|
15
|
+
send_blob_stream @representation, disposition: params[:disposition]
|
16
16
|
end
|
17
17
|
end
|
18
18
|
end
|
@@ -15,9 +15,9 @@ export function start() {
|
|
15
15
|
}
|
16
16
|
|
17
17
|
function didClick(event) {
|
18
|
-
const
|
19
|
-
if (
|
20
|
-
submitButtonsByForm.set(
|
18
|
+
const button = event.target.closest("button, input")
|
19
|
+
if (button && button.type === "submit" && button.form) {
|
20
|
+
submitButtonsByForm.set(button.form, button)
|
21
21
|
}
|
22
22
|
}
|
23
23
|
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ActiveStorage::PreviewImageJob < ActiveStorage::BaseJob
|
4
|
+
queue_as { ActiveStorage.queues[:preview_image] }
|
5
|
+
|
6
|
+
discard_on ActiveRecord::RecordNotFound, ActiveStorage::UnrepresentableError
|
7
|
+
retry_on ActiveStorage::IntegrityError, attempts: 10, wait: :polynomially_longer
|
8
|
+
|
9
|
+
def perform(blob, variations)
|
10
|
+
blob.preview({}).processed
|
11
|
+
|
12
|
+
variations.each do |transformations|
|
13
|
+
blob.preprocessed(transformations)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -3,10 +3,10 @@
|
|
3
3
|
class ActiveStorage::TransformJob < ActiveStorage::BaseJob
|
4
4
|
queue_as { ActiveStorage.queues[:transform] }
|
5
5
|
|
6
|
-
discard_on ActiveRecord::RecordNotFound
|
6
|
+
discard_on ActiveRecord::RecordNotFound, ActiveStorage::UnrepresentableError
|
7
7
|
retry_on ActiveStorage::IntegrityError, attempts: 10, wait: :polynomially_longer
|
8
8
|
|
9
9
|
def perform(blob, transformations)
|
10
|
-
blob.
|
10
|
+
blob.representation(transformations).processed
|
11
11
|
end
|
12
12
|
end
|
@@ -18,19 +18,17 @@ require "active_support/core_ext/module/delegation"
|
|
18
18
|
# # preloads blobs and variant records (if using `ActiveStorage.track_variants`)
|
19
19
|
# User.first.avatars.with_all_variant_records
|
20
20
|
class ActiveStorage::Attachment < ActiveStorage::Record
|
21
|
-
self.table_name = "active_storage_attachments"
|
22
|
-
|
23
21
|
##
|
24
22
|
# :method:
|
25
23
|
#
|
26
24
|
# Returns the associated record.
|
27
|
-
belongs_to :record, polymorphic: true, touch:
|
25
|
+
belongs_to :record, polymorphic: true, touch: ActiveStorage.touch_attachment_records
|
28
26
|
|
29
27
|
##
|
30
28
|
# :method:
|
31
29
|
#
|
32
30
|
# Returns the associated ActiveStorage::Blob.
|
33
|
-
belongs_to :blob, class_name: "ActiveStorage::Blob", autosave: true
|
31
|
+
belongs_to :blob, class_name: "ActiveStorage::Blob", autosave: true, inverse_of: :attachments
|
34
32
|
|
35
33
|
delegate_missing_to :blob
|
36
34
|
delegate :signed_id, to: :blob
|
@@ -44,7 +42,10 @@ class ActiveStorage::Attachment < ActiveStorage::Record
|
|
44
42
|
# Eager load all variant records on an attachment at once.
|
45
43
|
#
|
46
44
|
# User.first.avatars.with_all_variant_records
|
47
|
-
scope :with_all_variant_records, -> { includes(blob: {
|
45
|
+
scope :with_all_variant_records, -> { includes(blob: {
|
46
|
+
variant_records: { image_attachment: :blob },
|
47
|
+
preview_image_attachment: { blob: { variant_records: { image_attachment: :blob } } }
|
48
|
+
}) }
|
48
49
|
|
49
50
|
# Synchronously deletes the attachment and {purges the blob}[rdoc-ref:ActiveStorage::Blob#purge].
|
50
51
|
def purge
|
@@ -131,8 +132,18 @@ class ActiveStorage::Attachment < ActiveStorage::Record
|
|
131
132
|
end
|
132
133
|
|
133
134
|
def transform_variants_later
|
134
|
-
named_variants.
|
135
|
-
|
135
|
+
preprocessed_variations = named_variants.filter_map { |_name, named_variant|
|
136
|
+
if named_variant.preprocessed?(record)
|
137
|
+
named_variant.transformations
|
138
|
+
end
|
139
|
+
}
|
140
|
+
|
141
|
+
if blob.preview_image_needed_before_processing_variants? && preprocessed_variations.any?
|
142
|
+
blob.create_preview_image_later(preprocessed_variations)
|
143
|
+
else
|
144
|
+
preprocessed_variations.each do |transformations|
|
145
|
+
blob.preprocessed(transformations)
|
146
|
+
end
|
136
147
|
end
|
137
148
|
end
|
138
149
|
|
@@ -145,7 +156,7 @@ class ActiveStorage::Attachment < ActiveStorage::Record
|
|
145
156
|
end
|
146
157
|
|
147
158
|
def named_variants
|
148
|
-
record.attachment_reflections[name]&.named_variants
|
159
|
+
record.attachment_reflections[name]&.named_variants || {}
|
149
160
|
end
|
150
161
|
|
151
162
|
def transformations_by_name(transformations)
|
@@ -98,8 +98,16 @@ module ActiveStorage::Blob::Representable
|
|
98
98
|
variable? || previewable?
|
99
99
|
end
|
100
100
|
|
101
|
+
def preview_image_needed_before_processing_variants? # :nodoc:
|
102
|
+
previewable? && !preview_image.attached?
|
103
|
+
end
|
104
|
+
|
105
|
+
def create_preview_image_later(variations) # :nodoc:
|
106
|
+
ActiveStorage::PreviewImageJob.perform_later(self, variations) if representable?
|
107
|
+
end
|
108
|
+
|
101
109
|
def preprocessed(transformations) # :nodoc:
|
102
|
-
ActiveStorage::TransformJob.perform_later(self, transformations)
|
110
|
+
ActiveStorage::TransformJob.perform_later(self, transformations) if representable?
|
103
111
|
end
|
104
112
|
|
105
113
|
private
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveStorage::Blob::Servable # :nodoc:
|
4
|
+
def content_type_for_serving
|
5
|
+
forcibly_serve_as_binary? ? ActiveStorage.binary_content_type : content_type
|
6
|
+
end
|
7
|
+
|
8
|
+
def forced_disposition_for_serving
|
9
|
+
if forcibly_serve_as_binary? || !allowed_inline?
|
10
|
+
:attachment
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
def forcibly_serve_as_binary?
|
16
|
+
ActiveStorage.content_types_to_serve_as_binary.include?(content_type)
|
17
|
+
end
|
18
|
+
|
19
|
+
def allowed_inline?
|
20
|
+
ActiveStorage.content_types_allowed_inline.include?(content_type)
|
21
|
+
end
|
22
|
+
end
|
@@ -17,12 +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
|
-
|
24
|
-
self.table_name = "active_storage_blobs"
|
25
|
-
|
26
20
|
MINIMUM_TOKEN_LENGTH = 28
|
27
21
|
|
28
22
|
has_secure_token :key, length: MINIMUM_TOKEN_LENGTH
|
@@ -34,7 +28,7 @@ class ActiveStorage::Blob < ActiveStorage::Record
|
|
34
28
|
##
|
35
29
|
# :method:
|
36
30
|
#
|
37
|
-
# Returns the associated
|
31
|
+
# Returns the associated ActiveStorage::Attachment instances.
|
38
32
|
has_many :attachments
|
39
33
|
|
40
34
|
##
|
@@ -47,7 +41,7 @@ class ActiveStorage::Blob < ActiveStorage::Record
|
|
47
41
|
self.service_name ||= self.class.service&.name
|
48
42
|
end
|
49
43
|
|
50
|
-
after_update :
|
44
|
+
after_update :touch_attachments
|
51
45
|
|
52
46
|
after_update_commit :update_service_metadata, if: -> { content_type_previously_changed? || metadata_previously_changed? }
|
53
47
|
|
@@ -138,25 +132,49 @@ class ActiveStorage::Blob < ActiveStorage::Record
|
|
138
132
|
|
139
133
|
def scope_for_strict_loading # :nodoc:
|
140
134
|
if strict_loading_by_default? && ActiveStorage.track_variants
|
141
|
-
includes(
|
135
|
+
includes(
|
136
|
+
variant_records: { image_attachment: :blob },
|
137
|
+
preview_image_attachment: { blob: { variant_records: { image_attachment: :blob } } }
|
138
|
+
)
|
142
139
|
else
|
143
140
|
all
|
144
141
|
end
|
145
142
|
end
|
146
143
|
|
147
144
|
# Concatenate multiple blobs into a single "composed" blob.
|
148
|
-
def compose(blobs, filename:, content_type: nil, metadata: nil)
|
145
|
+
def compose(blobs, key: nil, filename:, content_type: nil, metadata: nil)
|
149
146
|
raise ActiveRecord::RecordNotSaved, "All blobs must be persisted." if blobs.any?(&:new_record?)
|
150
147
|
|
151
148
|
content_type ||= blobs.pluck(:content_type).compact.first
|
152
149
|
|
153
|
-
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|
|
154
151
|
combined_blob.compose(blobs.pluck(:key))
|
155
152
|
combined_blob.save!
|
156
153
|
end
|
157
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
|
158
171
|
end
|
159
172
|
|
173
|
+
include Analyzable
|
174
|
+
include Identifiable
|
175
|
+
include Representable
|
176
|
+
include Servable
|
177
|
+
|
160
178
|
# Returns a signed ID for this blob that's suitable for reference on the client-side without fear of tampering.
|
161
179
|
def signed_id(purpose: :blob_id, expires_in: nil, expires_at: nil)
|
162
180
|
super
|
@@ -226,16 +244,6 @@ class ActiveStorage::Blob < ActiveStorage::Record
|
|
226
244
|
service.headers_for_direct_upload key, filename: filename, content_type: content_type, content_length: byte_size, checksum: checksum, custom_metadata: custom_metadata
|
227
245
|
end
|
228
246
|
|
229
|
-
def content_type_for_serving # :nodoc:
|
230
|
-
forcibly_serve_as_binary? ? ActiveStorage.binary_content_type : content_type
|
231
|
-
end
|
232
|
-
|
233
|
-
def forced_disposition_for_serving # :nodoc:
|
234
|
-
if forcibly_serve_as_binary? || !allowed_inline?
|
235
|
-
:attachment
|
236
|
-
end
|
237
|
-
end
|
238
|
-
|
239
247
|
|
240
248
|
# Uploads the +io+ to the service on the +key+ for this blob. Blobs are intended to be immutable, so you shouldn't be
|
241
249
|
# using this method after a file has already been uploaded to fit with a blob. If you want to create a derivative blob,
|
@@ -342,8 +350,9 @@ class ActiveStorage::Blob < ActiveStorage::Record
|
|
342
350
|
raise ArgumentError, "io must be rewindable" unless io.respond_to?(:rewind)
|
343
351
|
|
344
352
|
OpenSSL::Digest::MD5.new.tap do |checksum|
|
345
|
-
|
346
|
-
|
353
|
+
read_buffer = "".b
|
354
|
+
while io.read(5.megabytes, read_buffer)
|
355
|
+
checksum << read_buffer
|
347
356
|
end
|
348
357
|
|
349
358
|
io.rewind
|
@@ -354,14 +363,6 @@ class ActiveStorage::Blob < ActiveStorage::Record
|
|
354
363
|
Marcel::MimeType.for io, name: filename.to_s, declared_type: content_type
|
355
364
|
end
|
356
365
|
|
357
|
-
def forcibly_serve_as_binary?
|
358
|
-
ActiveStorage.content_types_to_serve_as_binary.include?(content_type)
|
359
|
-
end
|
360
|
-
|
361
|
-
def allowed_inline?
|
362
|
-
ActiveStorage.content_types_allowed_inline.include?(content_type)
|
363
|
-
end
|
364
|
-
|
365
366
|
def web_image?
|
366
367
|
ActiveStorage.web_image_content_types.include?(content_type)
|
367
368
|
end
|
@@ -376,8 +377,14 @@ class ActiveStorage::Blob < ActiveStorage::Record
|
|
376
377
|
end
|
377
378
|
end
|
378
379
|
|
379
|
-
def
|
380
|
-
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|
|
381
388
|
attachment.touch
|
382
389
|
end
|
383
390
|
end
|