activestorage 7.2.3 → 8.0.0.beta1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of activestorage might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 94213ce5408fd1a4c67c6bf4854d2f2c55289813ef0297dfc33fb3325ec5dfd4
4
- data.tar.gz: 73de432409f6bb50456de14131e01c649b0172fcd5c0d5178b61b385cc236e37
3
+ metadata.gz: 90eb90580cb0faea4b29eef5ddf0dbc99dd1087158980f968561fe45c2dcb4d4
4
+ data.tar.gz: bdd0ced8684956539dee4f32ea7eacd16744c72e318aebc0bd815adfa72ffe73
5
5
  SHA512:
6
- metadata.gz: 48271c643e3a2a6ffbabdc398863f9452d3cdc2c01540b94a28f512fcc828d1792d13fd36ec05c890e3b02dc7d6fc33439c792eebbda2ab720479032307c947a
7
- data.tar.gz: 65acfc493d0aa029d4b533dd086cdeb9e35c04c6b4b4b6ee678101516bfc9428ffc477be92d5d49c5c1f6f43f6bed29b2c7ccbacf11f650e27fae34a779bb672
6
+ metadata.gz: 46465038ab95d65913a9f359af9b21fcb5b3ee9a37877b32eeabd7943de6373625d7ae51a9383099a89bd7d949ee6b5db37c5518656313121d8991b4e52e7667
7
+ data.tar.gz: 4f7590242bb707d2ed0c9b22871f2e00d28f683224341387c739b9771a85ab18e8655e1a913b2bdabb724bb694cb6b997f4b1c2771fa52a2b96ac1882593471a
data/CHANGELOG.md CHANGED
@@ -1,131 +1,23 @@
1
- ## Rails 7.2.3 (October 28, 2025) ##
1
+ ## Rails 8.0.0.beta1 (September 26, 2024) ##
2
2
 
3
- * Fix `config.active_storage.touch_attachment_records` to work with eager loading.
3
+ * Deprecate `ActiveStorage::Service::AzureStorageService`.
4
4
 
5
- *fatkodima*
5
+ *zzak*
6
6
 
7
- * A Blob will no longer autosave associated Attachment.
7
+ * Improve `ActiveStorage::Filename#sanitized` method to handle special characters more effectively.
8
+ Replace the characters `"*?<>` with `-` if they exist in the Filename to match the Filename convention of Win OS.
8
9
 
9
- This fixes an issue where a record with an attachment would have
10
- its dirty attributes reset, preventing your `after commit` callbacks
11
- on that record to behave as expected.
10
+ *Luong Viet Dung(Martin)*
12
11
 
13
- Note that this change doesn't require any changes on your application
14
- and is supposed to be internal. Active Storage Attachment will continue
15
- to be autosaved (through a different relation).
12
+ * Improve InvariableError, UnpreviewableError and UnrepresentableError message.
16
13
 
17
- *Edouard-chin*
14
+ Include Blob ID and content_type in the messages.
18
15
 
16
+ *Petrik de Heus*
19
17
 
20
- ## Rails 7.2.2.2 (August 13, 2025) ##
18
+ * Mark proxied files as `immutable` in their Cache-Control header
21
19
 
22
- * Remove dangerous transformations
20
+ *Nate Matykiewicz*
23
21
 
24
- [CVE-2025-24293]
25
22
 
26
- *Zack Deveau*
27
-
28
-
29
- ## Rails 7.2.2.1 (December 10, 2024) ##
30
-
31
- * No changes.
32
-
33
-
34
- ## Rails 7.2.2 (October 30, 2024) ##
35
-
36
- * No changes.
37
-
38
-
39
- ## Rails 7.2.1.2 (October 23, 2024) ##
40
-
41
- * No changes.
42
-
43
-
44
- ## Rails 7.2.1.1 (October 15, 2024) ##
45
-
46
- * No changes.
47
-
48
-
49
- ## Rails 7.2.1 (August 22, 2024) ##
50
-
51
- * No changes.
52
-
53
-
54
- ## Rails 7.2.0 (August 09, 2024) ##
55
-
56
- * Remove deprecated `config.active_storage.silence_invalid_content_types_warning`.
57
-
58
- *Rafael Mendonça França*
59
-
60
- * Remove deprecated `config.active_storage.replace_on_assign_to_many`.
61
-
62
- *Rafael Mendonça França*
63
-
64
- * Add support for custom `key` in `ActiveStorage::Blob#compose`.
65
-
66
- *Elvin Efendiev*
67
-
68
- * Add `image/webp` to `config.active_storage.web_image_content_types` when `load_defaults "7.2"`
69
- is set.
70
-
71
- *Lewis Buckley*
72
-
73
- * Fix JSON-encoding of `ActiveStorage::Filename` instances.
74
-
75
- *Jonathan del Strother*
76
-
77
- * Fix N+1 query when fetching preview images for non-image assets.
78
-
79
- *Aaron Patterson & Justin Searls*
80
-
81
- * Fix all Active Storage database related models to respect
82
- `ActiveRecord::Base.table_name_prefix` configuration.
83
-
84
- *Chedli Bourguiba*
85
-
86
- * Fix `ActiveStorage::Representations::ProxyController` not returning the proper
87
- preview image variant for previewable files.
88
-
89
- *Chedli Bourguiba*
90
-
91
- * Fix `ActiveStorage::Representations::ProxyController` to proxy untracked
92
- variants.
93
-
94
- *Chedli Bourguiba*
95
-
96
- * When using the `preprocessed: true` option, avoid enqueuing transform jobs
97
- for blobs that are not representable.
98
-
99
- *Chedli Bourguiba*
100
-
101
- * Prevent `ActiveStorage::Blob#preview` to generate a variant if an empty variation is passed.
102
-
103
- Calls to `#url`, `#key` or `#download` will now use the original preview
104
- image instead of generating a variant with the exact same dimensions.
105
-
106
- *Chedli Bourguiba*
107
-
108
- * Process preview image variant when calling `ActiveStorage::Preview#processed`.
109
-
110
- For example, `attached_pdf.preview(:thumb).processed` will now immediately
111
- generate the full-sized preview image and the `:thumb` variant of it.
112
- Previously, the `:thumb` variant would not be generated until a further call
113
- to e.g. `processed.url`.
114
-
115
- *Chedli Bourguiba* and *Jonathan Hefner*
116
-
117
- * Prevent `ActiveRecord::StrictLoadingViolationError` when strict loading is
118
- enabled and the variant of an Active Storage preview has already been
119
- processed (for example, by calling `ActiveStorage::Preview#url`).
120
-
121
- *Jonathan Hefner*
122
-
123
- * Fix `preprocessed: true` option for named variants of previewable files.
124
-
125
- *Nico Wenterodt*
126
-
127
- * Allow accepting `service` as a proc as well in `has_one_attached` and `has_many_attached`.
128
-
129
- *Yogesh Khater*
130
-
131
- Please check [7-1-stable](https://github.com/rails/rails/blob/7-1-stable/activestorage/CHANGELOG.md) for previous changes.
23
+ Please check [7-2-stable](https://github.com/rails/rails/blob/7-2-stable/activestorage/CHANGELOG.md) for previous changes.
data/README.md CHANGED
@@ -73,7 +73,7 @@ end
73
73
  ```erb
74
74
  <%= form_with model: @message, local: true do |form| %>
75
75
  <%= form.text_field :title, placeholder: "Title" %><br>
76
- <%= form.text_area :content %><br><br>
76
+ <%= form.textarea :content %><br><br>
77
77
 
78
78
  <%= form.file_field :images, multiple: true %><br>
79
79
  <%= form.submit %>
@@ -88,7 +88,7 @@ class MessagesController < ApplicationController
88
88
  end
89
89
 
90
90
  def create
91
- message = Message.create! params.require(:message).permit(:title, :content, images: [])
91
+ message = Message.create! params.expect(message: [ :title, :content, images: [] ])
92
92
  redirect_to message
93
93
  end
94
94
 
@@ -203,6 +203,6 @@ Bug reports for the Ruby on \Rails project can be filed here:
203
203
 
204
204
  * https://github.com/rails/rails/issues
205
205
 
206
- Feature requests should be discussed on the rubyonrails-core forum here:
206
+ Feature requests should be discussed on the rails-core mailing list here:
207
207
 
208
208
  * https://discuss.rubyonrails.org/c/rubyonrails-core
@@ -845,4 +845,4 @@ function autostart() {
845
845
 
846
846
  setTimeout(autostart, 1);
847
847
 
848
- export { DirectUpload, DirectUploadController, DirectUploadsController, start };
848
+ export { DirectUpload, DirectUploadController, DirectUploadsController, dispatchEvent, start };
@@ -822,6 +822,7 @@
822
822
  exports.DirectUpload = DirectUpload;
823
823
  exports.DirectUploadController = DirectUploadController;
824
824
  exports.DirectUploadsController = DirectUploadsController;
825
+ exports.dispatchEvent = dispatchEvent;
825
826
  exports.start = start;
826
827
  Object.defineProperty(exports, "__esModule", {
827
828
  value: true
@@ -11,7 +11,7 @@ class ActiveStorage::DirectUploadsController < ActiveStorage::BaseController
11
11
 
12
12
  private
13
13
  def blob_args
14
- params.require(:blob).permit(:filename, :byte_size, :checksum, :content_type, metadata: {}).to_h.symbolize_keys
14
+ params.expect(blob: [:filename, :byte_size, :checksum, :content_type, metadata: {}]).to_h.symbolize_keys
15
15
  end
16
16
 
17
17
  def direct_upload_json(blob)
@@ -25,13 +25,13 @@ class ActiveStorage::DiskController < ActiveStorage::BaseController
25
25
  named_disk_service(token[:service_name]).upload token[:key], request.body, checksum: token[:checksum]
26
26
  head :no_content
27
27
  else
28
- head ActionDispatch::Constants::UNPROCESSABLE_CONTENT
28
+ head :unprocessable_entity
29
29
  end
30
30
  else
31
31
  head :not_found
32
32
  end
33
33
  rescue ActiveStorage::IntegrityError
34
- head ActionDispatch::Constants::UNPROCESSABLE_CONTENT
34
+ head :unprocessable_entity
35
35
  end
36
36
 
37
37
  private
@@ -61,6 +61,15 @@ module ActiveStorage::Streaming
61
61
  blob.download do |chunk|
62
62
  stream.write chunk
63
63
  end
64
+ rescue ActiveStorage::FileNotFoundError
65
+ expires_now
66
+ head :not_found
67
+ rescue
68
+ # Status and caching headers are already set, but not commited.
69
+ # Change the status to 500 manually.
70
+ expires_now
71
+ head :internal_server_error
72
+ raise
64
73
  end
65
74
  end
66
75
  end
@@ -2,7 +2,8 @@ import { start } from "./ujs"
2
2
  import { DirectUpload } from "./direct_upload"
3
3
  import { DirectUploadController } from "./direct_upload_controller"
4
4
  import { DirectUploadsController } from "./direct_uploads_controller"
5
- export { start, DirectUpload, DirectUploadController, DirectUploadsController }
5
+ import { dispatchEvent } from "./helpers"
6
+ export { start, DirectUpload, DirectUploadController, DirectUploadsController, dispatchEvent }
6
7
 
7
8
  function autostart() {
8
9
  if (window.ActiveStorage) {
@@ -31,77 +31,11 @@ module ActiveStorage::Blob::Representable
31
31
  # Raises ActiveStorage::InvariableError if the variant processor cannot
32
32
  # transform the blob. To determine whether a blob is variable, call
33
33
  # ActiveStorage::Blob#variable?.
34
- #
35
- # ==== Options
36
- #
37
- # Options are defined by the {image_processing gem}[https://github.com/janko/image_processing],
38
- # and depend on which variant processor you are using:
39
- # {Vips}[https://github.com/janko/image_processing/blob/master/doc/vips.md] or
40
- # {MiniMagick}[https://github.com/janko/image_processing/blob/master/doc/minimagick.md].
41
- # However, both variant processors support the following options:
42
- #
43
- # [+:resize_to_limit+]
44
- # Downsizes the image to fit within the specified dimensions while retaining
45
- # the original aspect ratio. Will only resize the image if it's larger than
46
- # the specified dimensions.
47
- #
48
- # user.avatar.variant(resize_to_limit: [100, 100])
49
- #
50
- # [+:resize_to_fit+]
51
- # Resizes the image to fit within the specified dimensions while retaining
52
- # the original aspect ratio. Will downsize the image if it's larger than the
53
- # specified dimensions or upsize if it's smaller.
54
- #
55
- # user.avatar.variant(resize_to_fit: [100, 100])
56
- #
57
- # [+:resize_to_fill+]
58
- # Resizes the image to fill the specified dimensions while retaining the
59
- # original aspect ratio. If necessary, will crop the image in the larger
60
- # dimension.
61
- #
62
- # user.avatar.variant(resize_to_fill: [100, 100])
63
- #
64
- # [+:resize_and_pad+]
65
- # Resizes the image to fit within the specified dimensions while retaining
66
- # the original aspect ratio. If necessary, will pad the remaining area with
67
- # transparent color if source image has alpha channel, black otherwise.
68
- #
69
- # user.avatar.variant(resize_and_pad: [100, 100])
70
- #
71
- # [+:crop+]
72
- # Extracts an area from an image. The first two arguments are the left and
73
- # top edges of area to extract, while the last two arguments are the width
74
- # and height of the area to extract.
75
- #
76
- # user.avatar.variant(crop: [20, 50, 300, 300])
77
- #
78
- # [+:rotate+]
79
- # Rotates the image by the specified angle.
80
- #
81
- # user.avatar.variant(rotate: 90)
82
- #
83
- # Some options, including those listed above, can accept additional
84
- # processor-specific values which can be passed as a trailing hash:
85
- #
86
- # <!-- Vips supports configuring `crop` for many of its transformations -->
87
- # <%= image_tag user.avatar.variant(resize_to_fill: [100, 100, { crop: :centre }]) %>
88
- #
89
- # If migrating an existing application between MiniMagick and Vips, you will
90
- # need to update processor-specific options:
91
- #
92
- # <!-- MiniMagick -->
93
- # <%= image_tag user.avatar.variant(resize_to_limit: [100, 100], format: :jpeg,
94
- # sampling_factor: "4:2:0", strip: true, interlace: "JPEG", colorspace: "sRGB", quality: 80) %>
95
- #
96
- # <!-- Vips -->
97
- # <%= image_tag user.avatar.variant(resize_to_limit: [100, 100], format: :jpeg,
98
- # saver: { subsample_mode: "on", strip: true, interlace: true, quality: 80 }) %>
99
- #
100
34
  def variant(transformations)
101
35
  if variable?
102
36
  variant_class.new(self, ActiveStorage::Variation.wrap(transformations).default_to(default_variant_transformations))
103
37
  else
104
- raise ActiveStorage::InvariableError
38
+ raise ActiveStorage::InvariableError, "Can't transform blob with ID=#{id} and content_type=#{content_type}"
105
39
  end
106
40
  end
107
41
 
@@ -130,7 +64,7 @@ module ActiveStorage::Blob::Representable
130
64
  if previewable?
131
65
  ActiveStorage::Preview.new(self, transformations)
132
66
  else
133
- raise ActiveStorage::UnpreviewableError
67
+ raise ActiveStorage::UnpreviewableError, "No previewer found for blob with ID=#{id} and content_type=#{content_type}"
134
68
  end
135
69
  end
136
70
 
@@ -155,7 +89,7 @@ module ActiveStorage::Blob::Representable
155
89
  when variable?
156
90
  variant transformations
157
91
  else
158
- raise ActiveStorage::UnrepresentableError
92
+ raise ActiveStorage::UnrepresentableError, "No previewer found and can't transform blob with ID=#{id} and content_type=#{content_type}"
159
93
  end
160
94
  end
161
95
 
@@ -29,7 +29,7 @@ class ActiveStorage::Blob < ActiveStorage::Record
29
29
  # :method:
30
30
  #
31
31
  # Returns the associated ActiveStorage::Attachment instances.
32
- has_many :attachments, autosave: false
32
+ has_many :attachments
33
33
 
34
34
  ##
35
35
  # :singleton-method:
@@ -71,9 +71,8 @@ class ActiveStorage::Blob < ActiveStorage::Record
71
71
  end
72
72
 
73
73
  # Works like +find_signed+, but will raise an +ActiveSupport::MessageVerifier::InvalidSignature+
74
- # exception if the +signed_id+ has either expired, has a purpose mismatch, is for another record,
75
- # or has been tampered with. It will also raise an +ActiveRecord::RecordNotFound+ exception if
76
- # the valid signed id can't find a record.
74
+ # exception if the +signed_id+ has either expired, has a purpose mismatch, or has been tampered with.
75
+ # It will also raise an +ActiveRecord::RecordNotFound+ exception if the valid signed id can't find a record.
77
76
  def find_signed!(id, record: nil, purpose: :blob_id)
78
77
  super(id, purpose: purpose)
79
78
  end
@@ -152,6 +151,22 @@ class ActiveStorage::Blob < ActiveStorage::Record
152
151
  combined_blob.save!
153
152
  end
154
153
  end
154
+
155
+ def validate_service_configuration(service_name, model_class, association_name) # :nodoc:
156
+ if service_name
157
+ services.fetch(service_name) do
158
+ raise ArgumentError, "Cannot configure service #{service_name.inspect} for #{model_class}##{association_name}"
159
+ end
160
+ else
161
+ validate_global_service_configuration
162
+ end
163
+ end
164
+
165
+ def validate_global_service_configuration # :nodoc:
166
+ if connected? && table_exists? && Rails.configuration.active_storage.service.nil?
167
+ raise RuntimeError, "Missing Active Storage service name. Specify Active Storage service name for config.active_storage.service in config/environments/#{Rails.env}.rb"
168
+ end
169
+ end
155
170
  end
156
171
 
157
172
  include Analyzable
@@ -57,7 +57,7 @@ class ActiveStorage::Filename
57
57
  #
58
58
  # Characters considered unsafe for storage (e.g. \, $, and the RTL override character) are replaced with a dash.
59
59
  def sanitized
60
- @filename.encode(Encoding::UTF_8, invalid: :replace, undef: :replace, replace: "�").strip.tr("\u{202E}%$|:;/\t\r\n\\", "-")
60
+ @filename.encode(Encoding::UTF_8, invalid: :replace, undef: :replace, replace: "�").strip.tr("\u{202E}%$|:;/<>?*\"\t\r\n\\", "-")
61
61
  end
62
62
 
63
63
  # Returns the sanitized version of the filename.
@@ -121,7 +121,7 @@ module ActiveStorage
121
121
  service_name = record.attachment_reflections[name].options[:service_name]
122
122
  if service_name.is_a?(Proc)
123
123
  service_name = service_name.call(record)
124
- Attached::Model.validate_service_configuration(service_name, record.class, name)
124
+ ActiveStorage::Blob.validate_service_configuration(service_name, record.class, name)
125
125
  end
126
126
  service_name
127
127
  end
@@ -61,18 +61,16 @@ module ActiveStorage
61
61
  # There is no column defined on the model side, Active Storage takes
62
62
  # care of the mapping between your records and the attachment.
63
63
  #
64
- # To avoid N+1 queries, you can include the attached blobs in your query like so:
65
- #
66
- # User.with_attached_avatar
67
- #
68
64
  # Under the covers, this relationship is implemented as a +has_one+ association to a
69
65
  # ActiveStorage::Attachment record and a +has_one-through+ association to a
70
66
  # ActiveStorage::Blob record. These associations are available as +avatar_attachment+
71
67
  # and +avatar_blob+. But you shouldn't need to work with these associations directly in
72
68
  # most circumstances.
73
69
  #
74
- # The system has been designed to having you go through the ActiveStorage::Attached::One
75
- # proxy that provides the dynamic proxy to the associations and factory methods, like +attach+.
70
+ # Instead, +has_one_attached+ generates an ActiveStorage::Attached::One proxy to
71
+ # provide access to the associations and factory methods, like +attach+:
72
+ #
73
+ # user.avatar.attach(uploaded_file)
76
74
  #
77
75
  # The +:dependent+ option defaults to +:purge_later+. This means the attachment will be
78
76
  # purged (i.e. destroyed) in the background whenever the record is destroyed.
@@ -92,6 +90,10 @@ module ActiveStorage
92
90
  # has_one_attached :avatar, service: ->(user) { user.in_europe_region? ? :s3_europe : :s3_usa }
93
91
  # end
94
92
  #
93
+ # To avoid N+1 queries, you can include the attached blobs in your query like so:
94
+ #
95
+ # User.with_attached_avatar
96
+ #
95
97
  # If you need to enable +strict_loading+ to prevent lazy loading of attachment,
96
98
  # pass the +:strict_loading+ option. You can do:
97
99
  #
@@ -104,7 +106,7 @@ module ActiveStorage
104
106
  # <tt>active_storage_attachments.record_type</tt> polymorphic type column of
105
107
  # the corresponding rows.
106
108
  def has_one_attached(name, dependent: :purge_later, service: nil, strict_loading: false)
107
- Attached::Model.validate_service_configuration(service, self, name) unless service.is_a?(Proc)
109
+ ActiveStorage::Blob.validate_service_configuration(service, self, name) unless service.is_a?(Proc)
108
110
 
109
111
  generated_association_methods.class_eval <<-CODE, __FILE__, __LINE__ + 1
110
112
  # frozen_string_literal: true
@@ -161,18 +163,16 @@ module ActiveStorage
161
163
  # There are no columns defined on the model side, Active Storage takes
162
164
  # care of the mapping between your records and the attachments.
163
165
  #
164
- # To avoid N+1 queries, you can include the attached blobs in your query like so:
165
- #
166
- # Gallery.where(user: Current.user).with_attached_photos
167
- #
168
166
  # Under the covers, this relationship is implemented as a +has_many+ association to a
169
167
  # ActiveStorage::Attachment record and a +has_many-through+ association to a
170
168
  # ActiveStorage::Blob record. These associations are available as +photos_attachments+
171
169
  # and +photos_blobs+. But you shouldn't need to work with these associations directly in
172
170
  # most circumstances.
173
171
  #
174
- # The system has been designed to having you go through the ActiveStorage::Attached::Many
175
- # proxy that provides the dynamic proxy to the associations and factory methods, like +#attach+.
172
+ # Instead, +has_many_attached+ generates an ActiveStorage::Attached::Many proxy to
173
+ # provide access to the associations and factory methods, like +attach+:
174
+ #
175
+ # user.photos.attach(uploaded_file)
176
176
  #
177
177
  # The +:dependent+ option defaults to +:purge_later+. This means the attachments will be
178
178
  # purged (i.e. destroyed) in the background whenever the record is destroyed.
@@ -192,6 +192,10 @@ module ActiveStorage
192
192
  # has_many_attached :photos, service: ->(gallery) { gallery.personal? ? :personal_s3 : :s3 }
193
193
  # end
194
194
  #
195
+ # To avoid N+1 queries, you can include the attached blobs in your query like so:
196
+ #
197
+ # Gallery.where(user: Current.user).with_attached_photos
198
+ #
195
199
  # If you need to enable +strict_loading+ to prevent lazy loading of attachments,
196
200
  # pass the +:strict_loading+ option. You can do:
197
201
  #
@@ -204,7 +208,7 @@ module ActiveStorage
204
208
  # <tt>active_storage_attachments.record_type</tt> polymorphic type column of
205
209
  # the corresponding rows.
206
210
  def has_many_attached(name, dependent: :purge_later, service: nil, strict_loading: false)
207
- Attached::Model.validate_service_configuration(service, self, name) unless service.is_a?(Proc)
211
+ ActiveStorage::Blob.validate_service_configuration(service, self, name) unless service.is_a?(Proc)
208
212
 
209
213
  generated_association_methods.class_eval <<-CODE, __FILE__, __LINE__ + 1
210
214
  # frozen_string_literal: true
@@ -255,25 +259,6 @@ module ActiveStorage
255
259
  end
256
260
  end
257
261
 
258
- class << self
259
- def validate_service_configuration(service_name, model_class, association_name) # :nodoc:
260
- if service_name
261
- ActiveStorage::Blob.services.fetch(service_name) do
262
- raise ArgumentError, "Cannot configure service #{service_name.inspect} for #{model_class}##{association_name}"
263
- end
264
- else
265
- validate_global_service_configuration(model_class)
266
- end
267
- end
268
-
269
- private
270
- def validate_global_service_configuration(model_class)
271
- if model_class.connected? && ActiveStorage::Blob.table_exists? && Rails.configuration.active_storage.service.nil?
272
- raise RuntimeError, "Missing Active Storage service name. Specify Active Storage service name for config.active_storage.service in config/environments/#{Rails.env}.rb"
273
- end
274
- end
275
- end
276
-
277
262
  def attachment_changes # :nodoc:
278
263
  @attachment_changes ||= {}
279
264
  end
@@ -84,10 +84,6 @@ module ActiveStorage
84
84
  end
85
85
 
86
86
  initializer "active_storage.configs" do
87
- config.before_initialize do |app|
88
- ActiveStorage.touch_attachment_records = app.config.active_storage.touch_attachment_records != false
89
- end
90
-
91
87
  config.after_initialize do |app|
92
88
  ActiveStorage.logger = app.config.active_storage.logger || Rails.logger
93
89
  ActiveStorage.variant_processor = app.config.active_storage.variant_processor || :mini_magick
@@ -116,6 +112,7 @@ module ActiveStorage
116
112
  ActiveStorage.variable_content_types = app.config.active_storage.variable_content_types || []
117
113
  ActiveStorage.web_image_content_types = app.config.active_storage.web_image_content_types || []
118
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
119
116
  ActiveStorage.service_urls_expire_in = app.config.active_storage.service_urls_expire_in || 5.minutes
120
117
  ActiveStorage.urls_expire_in = app.config.active_storage.urls_expire_in
121
118
  ActiveStorage.content_types_allowed_inline = app.config.active_storage.content_types_allowed_inline || []
@@ -50,7 +50,7 @@ module ActiveStorage
50
50
  # by ActiveSupport::Testing::FileFixtures.file_fixture, and upload
51
51
  # the file to the Service
52
52
  #
53
- # ==== Examples
53
+ # === Examples
54
54
  #
55
55
  # # tests/fixtures/active_storage/blobs.yml
56
56
  # second_thumbnail_blob: <%= ActiveStorage::FixtureSet.blob(
@@ -7,10 +7,10 @@ module ActiveStorage
7
7
  end
8
8
 
9
9
  module VERSION
10
- MAJOR = 7
11
- MINOR = 2
12
- TINY = 3
13
- PRE = nil
10
+ MAJOR = 8
11
+ MINOR = 0
12
+ TINY = 0
13
+ PRE = "beta1"
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
16
16
  end
@@ -15,6 +15,13 @@ module ActiveStorage
15
15
  attr_reader :client, :container, :signer
16
16
 
17
17
  def initialize(storage_account_name:, storage_access_key:, container:, public: false, **options)
18
+ ActiveStorage.deprecator.warn <<~MSG.squish
19
+ `ActiveStorage::Service::AzureStorageService` is deprecated and will be
20
+ removed in Rails 8.1.
21
+ Please try the `azure-blob` gem instead.
22
+ This gem is not maintained by the Rails team, so please test your applications before deploying to production.
23
+ MSG
24
+
18
25
  @client = Azure::Storage::Blob::BlobService.create(storage_account_name: storage_account_name, storage_access_key: storage_access_key, **options)
19
26
  @signer = Azure::Storage::Common::Core::Auth::SharedAccessSignature.new(storage_account_name, storage_access_key)
20
27
  @container = container
@@ -30,6 +30,13 @@ module ActiveStorage
30
30
 
31
31
  def initialize(primary:, mirrors:)
32
32
  @primary, @mirrors = primary, mirrors
33
+ @executor = Concurrent::ThreadPoolExecutor.new(
34
+ min_threads: 1,
35
+ max_threads: mirrors.size,
36
+ max_queue: 0,
37
+ fallback_policy: :caller_runs,
38
+ idle_time: 60
39
+ )
33
40
  end
34
41
 
35
42
  # Upload the +io+ to the +key+ specified to all services. The upload to the primary service is done synchronously
@@ -75,10 +82,12 @@ module ActiveStorage
75
82
  end
76
83
 
77
84
  def perform_across_services(method, *args)
78
- # FIXME: Convert to be threaded
79
- each_service.collect do |service|
80
- service.public_send method, *args
85
+ tasks = each_service.collect do |service|
86
+ Concurrent::Promise.execute(executor: @executor) do
87
+ service.public_send method, *args
88
+ end
81
89
  end
90
+ tasks.each(&:value!)
82
91
  end
83
92
  end
84
93
  end
@@ -16,7 +16,6 @@ module ActiveStorage
16
16
 
17
17
  def initialize(bucket:, upload: {}, public: false, **options)
18
18
  @client = Aws::S3::Resource.new(**options)
19
- @transfer_manager = Aws::S3::TransferManager.new(client: @client.client) if defined?(Aws::S3::TransferManager)
20
19
  @bucket = @client.bucket(bucket)
21
20
 
22
21
  @multipart_upload_threshold = upload.delete(:multipart_threshold) || 100.megabytes
@@ -101,8 +100,7 @@ module ActiveStorage
101
100
  def compose(source_keys, destination_key, filename: nil, content_type: nil, disposition: nil, custom_metadata: {})
102
101
  content_disposition = content_disposition_with(type: disposition, filename: filename) if disposition && filename
103
102
 
104
- upload_stream(
105
- key: destination_key,
103
+ object_for(destination_key).upload_stream(
106
104
  content_type: content_type,
107
105
  content_disposition: content_disposition,
108
106
  part_size: MINIMUM_UPLOAD_PART_SIZE,
@@ -118,14 +116,6 @@ module ActiveStorage
118
116
  end
119
117
 
120
118
  private
121
- def upload_stream(key:, **options, &block)
122
- if @transfer_manager
123
- @transfer_manager.upload_stream(key: key, bucket: bucket.name, **options, &block)
124
- else
125
- object_for(key).upload_stream(**options, &block)
126
- end
127
- end
128
-
129
119
  def private_url(key, expires_in:, filename:, disposition:, content_type:, **client_opts)
130
120
  object_for(key).presigned_url :get, expires_in: expires_in.to_i,
131
121
  response_content_disposition: content_disposition_with(type: disposition, filename: filename),
@@ -136,6 +126,7 @@ module ActiveStorage
136
126
  object_for(key).public_url(**client_opts)
137
127
  end
138
128
 
129
+
139
130
  MAXIMUM_UPLOAD_PARTS_COUNT = 10000
140
131
  MINIMUM_UPLOAD_PART_SIZE = 5.megabytes
141
132
 
@@ -148,18 +139,12 @@ module ActiveStorage
148
139
  def upload_with_multipart(key, io, content_type: nil, content_disposition: nil, custom_metadata: {})
149
140
  part_size = [ io.size.fdiv(MAXIMUM_UPLOAD_PARTS_COUNT).ceil, MINIMUM_UPLOAD_PART_SIZE ].max
150
141
 
151
- upload_stream(
152
- key: key,
153
- content_type: content_type,
154
- content_disposition: content_disposition,
155
- part_size: part_size,
156
- metadata: custom_metadata,
157
- **upload_options
158
- ) do |out|
142
+ object_for(key).upload_stream(content_type: content_type, content_disposition: content_disposition, part_size: part_size, metadata: custom_metadata, **upload_options) do |out|
159
143
  IO.copy_stream(io, out)
160
144
  end
161
145
  end
162
146
 
147
+
163
148
  def object_for(key)
164
149
  bucket.object(key)
165
150
  end
@@ -72,6 +72,7 @@ module ActiveStorage
72
72
  "annotate",
73
73
  "antialias",
74
74
  "append",
75
+ "apply",
75
76
  "attenuate",
76
77
  "authenticate",
77
78
  "auto_gamma",
@@ -212,6 +213,7 @@ module ActiveStorage
212
213
  "linewidth",
213
214
  "liquid_rescale",
214
215
  "list",
216
+ "loader",
215
217
  "log",
216
218
  "loop",
217
219
  "lowlight_color",
@@ -274,6 +276,7 @@ module ActiveStorage
274
276
  "rotate",
275
277
  "sample",
276
278
  "sampling_factor",
279
+ "saver",
277
280
  "scale",
278
281
  "scene",
279
282
  "screen",
metadata CHANGED
@@ -1,13 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activestorage
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.2.3
4
+ version: 8.0.0.beta1
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Heinemeier Hansson
8
+ autorequire:
8
9
  bindir: bin
9
10
  cert_chain: []
10
- date: 1980-01-02 00:00:00.000000000 Z
11
+ date: 2024-09-26 00:00:00.000000000 Z
11
12
  dependencies:
12
13
  - !ruby/object:Gem::Dependency
13
14
  name: activesupport
@@ -15,56 +16,56 @@ dependencies:
15
16
  requirements:
16
17
  - - '='
17
18
  - !ruby/object:Gem::Version
18
- version: 7.2.3
19
+ version: 8.0.0.beta1
19
20
  type: :runtime
20
21
  prerelease: false
21
22
  version_requirements: !ruby/object:Gem::Requirement
22
23
  requirements:
23
24
  - - '='
24
25
  - !ruby/object:Gem::Version
25
- version: 7.2.3
26
+ version: 8.0.0.beta1
26
27
  - !ruby/object:Gem::Dependency
27
28
  name: actionpack
28
29
  requirement: !ruby/object:Gem::Requirement
29
30
  requirements:
30
31
  - - '='
31
32
  - !ruby/object:Gem::Version
32
- version: 7.2.3
33
+ version: 8.0.0.beta1
33
34
  type: :runtime
34
35
  prerelease: false
35
36
  version_requirements: !ruby/object:Gem::Requirement
36
37
  requirements:
37
38
  - - '='
38
39
  - !ruby/object:Gem::Version
39
- version: 7.2.3
40
+ version: 8.0.0.beta1
40
41
  - !ruby/object:Gem::Dependency
41
42
  name: activejob
42
43
  requirement: !ruby/object:Gem::Requirement
43
44
  requirements:
44
45
  - - '='
45
46
  - !ruby/object:Gem::Version
46
- version: 7.2.3
47
+ version: 8.0.0.beta1
47
48
  type: :runtime
48
49
  prerelease: false
49
50
  version_requirements: !ruby/object:Gem::Requirement
50
51
  requirements:
51
52
  - - '='
52
53
  - !ruby/object:Gem::Version
53
- version: 7.2.3
54
+ version: 8.0.0.beta1
54
55
  - !ruby/object:Gem::Dependency
55
56
  name: activerecord
56
57
  requirement: !ruby/object:Gem::Requirement
57
58
  requirements:
58
59
  - - '='
59
60
  - !ruby/object:Gem::Version
60
- version: 7.2.3
61
+ version: 8.0.0.beta1
61
62
  type: :runtime
62
63
  prerelease: false
63
64
  version_requirements: !ruby/object:Gem::Requirement
64
65
  requirements:
65
66
  - - '='
66
67
  - !ruby/object:Gem::Version
67
- version: 7.2.3
68
+ version: 8.0.0.beta1
68
69
  - !ruby/object:Gem::Dependency
69
70
  name: marcel
70
71
  requirement: !ruby/object:Gem::Requirement
@@ -189,11 +190,12 @@ licenses:
189
190
  - MIT
190
191
  metadata:
191
192
  bug_tracker_uri: https://github.com/rails/rails/issues
192
- changelog_uri: https://github.com/rails/rails/blob/v7.2.3/activestorage/CHANGELOG.md
193
- documentation_uri: https://api.rubyonrails.org/v7.2.3/
193
+ changelog_uri: https://github.com/rails/rails/blob/v8.0.0.beta1/activestorage/CHANGELOG.md
194
+ documentation_uri: https://api.rubyonrails.org/v8.0.0.beta1/
194
195
  mailing_list_uri: https://discuss.rubyonrails.org/c/rubyonrails-talk
195
- source_code_uri: https://github.com/rails/rails/tree/v7.2.3/activestorage
196
+ source_code_uri: https://github.com/rails/rails/tree/v8.0.0.beta1/activestorage
196
197
  rubygems_mfa_required: 'true'
198
+ post_install_message:
197
199
  rdoc_options: []
198
200
  require_paths:
199
201
  - lib
@@ -201,14 +203,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
201
203
  requirements:
202
204
  - - ">="
203
205
  - !ruby/object:Gem::Version
204
- version: 3.1.0
206
+ version: 3.2.0
205
207
  required_rubygems_version: !ruby/object:Gem::Requirement
206
208
  requirements:
207
209
  - - ">="
208
210
  - !ruby/object:Gem::Version
209
211
  version: '0'
210
212
  requirements: []
211
- rubygems_version: 3.6.9
213
+ rubygems_version: 3.5.16
214
+ signing_key:
212
215
  specification_version: 4
213
216
  summary: Local and cloud file storage framework.
214
217
  test_files: []