activestorage 7.2.2.1 → 8.1.3

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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +126 -55
  3. data/README.md +8 -5
  4. data/app/assets/javascripts/activestorage.esm.js +38 -2
  5. data/app/assets/javascripts/activestorage.js +38 -1
  6. data/app/controllers/active_storage/direct_uploads_controller.rb +1 -1
  7. data/app/controllers/active_storage/disk_controller.rb +6 -2
  8. data/app/controllers/concerns/active_storage/streaming.rb +17 -1
  9. data/app/javascript/activestorage/direct_upload_controller.js +48 -1
  10. data/app/javascript/activestorage/index.js +2 -1
  11. data/app/models/active_storage/blob/representable.rb +71 -5
  12. data/app/models/active_storage/blob.rb +25 -21
  13. data/app/models/active_storage/filename.rb +2 -1
  14. data/app/models/active_storage/variant.rb +12 -12
  15. data/app/models/active_storage/variation.rb +1 -1
  16. data/lib/active_storage/analyzer/image_analyzer/image_magick.rb +11 -4
  17. data/lib/active_storage/analyzer/image_analyzer/vips.rb +23 -5
  18. data/lib/active_storage/analyzer/image_analyzer.rb +5 -0
  19. data/lib/active_storage/attached/changes/create_one.rb +1 -1
  20. data/lib/active_storage/attached/model.rb +41 -18
  21. data/lib/active_storage/attached.rb +0 -1
  22. data/lib/active_storage/engine.rb +38 -7
  23. data/lib/active_storage/errors.rb +4 -0
  24. data/lib/active_storage/fixture_set.rb +1 -1
  25. data/lib/active_storage/gem_version.rb +4 -4
  26. data/lib/active_storage/log_subscriber.rb +1 -1
  27. data/lib/active_storage/service/configurator.rb +6 -0
  28. data/lib/active_storage/service/disk_service.rb +46 -2
  29. data/lib/active_storage/service/gcs_service.rb +15 -5
  30. data/lib/active_storage/service/mirror_service.rb +13 -4
  31. data/lib/active_storage/service/registry.rb +6 -0
  32. data/lib/active_storage/service/s3_service.rb +19 -4
  33. data/lib/active_storage/service.rb +5 -1
  34. data/lib/active_storage/structured_event_subscriber.rb +79 -0
  35. data/lib/active_storage/transformers/image_magick.rb +72 -0
  36. data/lib/active_storage/transformers/image_processing_transformer.rb +5 -67
  37. data/lib/active_storage/transformers/null_transformer.rb +12 -0
  38. data/lib/active_storage/transformers/vips.rb +11 -0
  39. data/lib/active_storage.rb +19 -3
  40. metadata +19 -19
  41. data/lib/active_storage/service/azure_storage_service.rb +0 -194
@@ -144,6 +144,21 @@ module ActiveStorage
144
144
  end
145
145
  end
146
146
 
147
+ # Returns the IAM client used for direct uploads and signed URLs.
148
+ # By default, the authorization for the IAM client is set to
149
+ # {Application Default Credentials}[https://docs.cloud.google.com/docs/authentication/application-default-credentials],
150
+ # fetched once at instantiation time, then refreshed automatically when expired.
151
+ # This can be set to a different value to use other authorization methods.
152
+ #
153
+ # ActiveStorage::Blob.service.iam_client.authorization = Google::Auth::ImpersonatedServiceAccountCredentials.new(options)
154
+ def iam_client
155
+ @iam_client ||= Google::Apis::IamcredentialsV1::IAMCredentialsService.new.tap do |client|
156
+ client.authorization ||= Google::Auth.get_application_default(["https://www.googleapis.com/auth/iam"])
157
+ rescue
158
+ nil
159
+ end
160
+ end
161
+
147
162
  private
148
163
  def private_url(key, expires_in:, filename:, content_type:, disposition:, **)
149
164
  args = {
@@ -211,11 +226,6 @@ module ActiveStorage
211
226
  def signer
212
227
  # https://googleapis.dev/ruby/google-cloud-storage/latest/Google/Cloud/Storage/Project.html#signed_url-instance_method
213
228
  lambda do |string_to_sign|
214
- iam_client = Google::Apis::IamcredentialsV1::IAMCredentialsService.new
215
-
216
- scopes = ["https://www.googleapis.com/auth/iam"]
217
- iam_client.authorization = Google::Auth.get_application_default(scopes)
218
-
219
229
  request = Google::Apis::IamcredentialsV1::SignBlobRequest.new(
220
230
  payload: string_to_sign
221
231
  )
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/core_ext/module/delegation"
4
3
 
5
4
  module ActiveStorage
6
5
  # = Active Storage Mirror \Service
@@ -30,6 +29,14 @@ module ActiveStorage
30
29
 
31
30
  def initialize(primary:, mirrors:)
32
31
  @primary, @mirrors = primary, mirrors
32
+ @executor = Concurrent::ThreadPoolExecutor.new(
33
+ name: "ActiveStorage-mirror-service",
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
@@ -22,6 +22,12 @@ module ActiveStorage
22
22
  end
23
23
  end
24
24
 
25
+ def inspect # :nodoc:
26
+ attrs = configurations.any? ?
27
+ " configurations=[#{configurations.keys.map(&:inspect).join(", ")}]" : ""
28
+ "#<#{self.class}#{attrs}>"
29
+ end
30
+
25
31
  private
26
32
  attr_reader :configurations, :services
27
33
 
@@ -16,6 +16,7 @@ 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)
19
20
  @bucket = @client.bucket(bucket)
20
21
 
21
22
  @multipart_upload_threshold = upload.delete(:multipart_threshold) || 100.megabytes
@@ -100,7 +101,8 @@ module ActiveStorage
100
101
  def compose(source_keys, destination_key, filename: nil, content_type: nil, disposition: nil, custom_metadata: {})
101
102
  content_disposition = content_disposition_with(type: disposition, filename: filename) if disposition && filename
102
103
 
103
- object_for(destination_key).upload_stream(
104
+ upload_stream(
105
+ key: destination_key,
104
106
  content_type: content_type,
105
107
  content_disposition: content_disposition,
106
108
  part_size: MINIMUM_UPLOAD_PART_SIZE,
@@ -116,6 +118,14 @@ module ActiveStorage
116
118
  end
117
119
 
118
120
  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
+
119
129
  def private_url(key, expires_in:, filename:, disposition:, content_type:, **client_opts)
120
130
  object_for(key).presigned_url :get, expires_in: expires_in.to_i,
121
131
  response_content_disposition: content_disposition_with(type: disposition, filename: filename),
@@ -126,7 +136,6 @@ module ActiveStorage
126
136
  object_for(key).public_url(**client_opts)
127
137
  end
128
138
 
129
-
130
139
  MAXIMUM_UPLOAD_PARTS_COUNT = 10000
131
140
  MINIMUM_UPLOAD_PART_SIZE = 5.megabytes
132
141
 
@@ -139,12 +148,18 @@ module ActiveStorage
139
148
  def upload_with_multipart(key, io, content_type: nil, content_disposition: nil, custom_metadata: {})
140
149
  part_size = [ io.size.fdiv(MAXIMUM_UPLOAD_PARTS_COUNT).ceil, MINIMUM_UPLOAD_PART_SIZE ].max
141
150
 
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|
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|
143
159
  IO.copy_stream(io, out)
144
160
  end
145
161
  end
146
162
 
147
-
148
163
  def object_for(key)
149
164
  bucket.object(key)
150
165
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_storage/log_subscriber"
4
+ require "active_storage/structured_event_subscriber"
4
5
  require "active_storage/downloader"
5
6
  require "action_dispatch"
6
7
  require "action_dispatch/http/content_disposition"
@@ -15,7 +16,6 @@ module ActiveStorage
15
16
  # * +Disk+, to manage attachments saved directly on the hard drive.
16
17
  # * +GCS+, to manage attachments through Google Cloud Storage.
17
18
  # * +S3+, to manage attachments through Amazon S3.
18
- # * +AzureStorage+, to manage attachments through Microsoft Azure Storage.
19
19
  # * +Mirror+, to be able to use several services to manage attachments.
20
20
  #
21
21
  # Inside a \Rails application, you can set-up your services through the
@@ -148,6 +148,10 @@ module ActiveStorage
148
148
  @public
149
149
  end
150
150
 
151
+ def inspect # :nodoc:
152
+ "#<#{self.class}#{name.present? ? " name=#{name.inspect}" : ""}>"
153
+ end
154
+
151
155
  private
152
156
  def private_url(key, expires_in:, filename:, disposition:, content_type:, **)
153
157
  raise NotImplementedError
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/structured_event_subscriber"
4
+
5
+ module ActiveStorage
6
+ class StructuredEventSubscriber < ActiveSupport::StructuredEventSubscriber # :nodoc:
7
+ def service_upload(event)
8
+ emit_event("active_storage.service_upload",
9
+ key: event.payload[:key],
10
+ checksum: event.payload[:checksum],
11
+ duration_ms: event.duration.round(2),
12
+ )
13
+ end
14
+
15
+ def service_download(event)
16
+ emit_event("active_storage.service_download",
17
+ key: event.payload[:key],
18
+ duration_ms: event.duration.round(2),
19
+ )
20
+ end
21
+
22
+ def service_streaming_download(event)
23
+ emit_event("active_storage.service_streaming_download",
24
+ key: event.payload[:key],
25
+ duration_ms: event.duration.round(2),
26
+ )
27
+ end
28
+
29
+ def preview(event)
30
+ emit_event("active_storage.preview",
31
+ key: event.payload[:key],
32
+ duration_ms: event.duration.round(2),
33
+ )
34
+ end
35
+
36
+ def service_delete(event)
37
+ emit_event("active_storage.service_delete",
38
+ key: event.payload[:key],
39
+ duration_ms: event.duration.round(2),
40
+ )
41
+ end
42
+
43
+ def service_delete_prefixed(event)
44
+ emit_event("active_storage.service_delete_prefixed",
45
+ prefix: event.payload[:prefix],
46
+ duration_ms: event.duration.round(2),
47
+ )
48
+ end
49
+
50
+ def service_exist(event)
51
+ emit_debug_event("active_storage.service_exist",
52
+ key: event.payload[:key],
53
+ exist: event.payload[:exist],
54
+ duration_ms: event.duration.round(2),
55
+ )
56
+ end
57
+ debug_only :service_exist
58
+
59
+ def service_url(event)
60
+ emit_debug_event("active_storage.service_url",
61
+ key: event.payload[:key],
62
+ url: event.payload[:url],
63
+ duration_ms: event.duration.round(2),
64
+ )
65
+ end
66
+ debug_only :service_url
67
+
68
+ def service_mirror(event)
69
+ emit_debug_event("active_storage.service_mirror",
70
+ key: event.payload[:key],
71
+ checksum: event.payload[:checksum],
72
+ duration_ms: event.duration.round(2),
73
+ )
74
+ end
75
+ debug_only :service_mirror
76
+ end
77
+ end
78
+
79
+ ActiveStorage::StructuredEventSubscriber.attach_to :active_storage
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveStorage
4
+ module Transformers
5
+ class ImageMagick < ImageProcessingTransformer
6
+ private
7
+ def processor
8
+ ImageProcessing::MiniMagick
9
+ end
10
+
11
+ def validate_transformation(name, argument)
12
+ method_name = name.to_s.tr("-", "_")
13
+
14
+ unless ActiveStorage.supported_image_processing_methods.include?(method_name)
15
+ raise UnsupportedImageProcessingMethod, <<~ERROR.squish
16
+ The provided transformation method is not supported: #{method_name}.
17
+ ERROR
18
+ end
19
+
20
+ if argument.present?
21
+ if argument.is_a?(String) || argument.is_a?(Symbol)
22
+ validate_arg_string(argument)
23
+ elsif argument.is_a?(Array)
24
+ validate_arg_array(argument)
25
+ elsif argument.is_a?(Hash)
26
+ validate_arg_hash(argument)
27
+ end
28
+ end
29
+
30
+ super
31
+ end
32
+
33
+ def validate_arg_string(argument)
34
+ unsupported_arguments = ActiveStorage.unsupported_image_processing_arguments.any? do |bad_arg|
35
+ argument.to_s.downcase.include?(bad_arg)
36
+ end
37
+
38
+ raise UnsupportedImageProcessingArgument if unsupported_arguments
39
+ end
40
+
41
+ def validate_arg_array(argument)
42
+ argument.each do |arg|
43
+ if arg.is_a?(Integer) || arg.is_a?(Float)
44
+ next
45
+ elsif arg.is_a?(String) || arg.is_a?(Symbol)
46
+ validate_arg_string(arg)
47
+ elsif arg.is_a?(Array)
48
+ validate_arg_array(arg)
49
+ elsif arg.is_a?(Hash)
50
+ validate_arg_hash(arg)
51
+ end
52
+ end
53
+ end
54
+
55
+ def validate_arg_hash(argument)
56
+ argument.each do |key, value|
57
+ validate_arg_string(key)
58
+
59
+ if value.is_a?(Integer) || value.is_a?(Float)
60
+ next
61
+ elsif value.is_a?(String) || value.is_a?(Symbol)
62
+ validate_arg_string(value)
63
+ elsif value.is_a?(Array)
64
+ validate_arg_array(value)
65
+ elsif value.is_a?(Hash)
66
+ validate_arg_hash(value)
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -25,22 +25,9 @@ module ActiveStorage
25
25
  call
26
26
  end
27
27
 
28
- def processor
29
- ImageProcessing.const_get(ActiveStorage.variant_processor.to_s.camelize)
30
- end
31
-
32
28
  def operations
33
29
  transformations.each_with_object([]) do |(name, argument), list|
34
- if ActiveStorage.variant_processor == :mini_magick
35
- validate_transformation(name, argument)
36
- end
37
-
38
- if name.to_s == "combine_options"
39
- raise ArgumentError, <<~ERROR.squish
40
- Active Storage's ImageProcessing transformer doesn't support :combine_options,
41
- as it always generates a single command.
42
- ERROR
43
- end
30
+ validate_transformation(name, argument)
44
31
 
45
32
  if argument.present?
46
33
  list << [ name, argument ]
@@ -49,61 +36,12 @@ module ActiveStorage
49
36
  end
50
37
 
51
38
  def validate_transformation(name, argument)
52
- method_name = name.to_s.tr("-", "_")
53
-
54
- unless ActiveStorage.supported_image_processing_methods.any? { |method| method_name == method }
55
- raise UnsupportedImageProcessingMethod, <<~ERROR.squish
56
- One or more of the provided transformation methods is not supported.
39
+ if name.to_s == "combine_options"
40
+ raise ArgumentError, <<~ERROR.squish
41
+ Active Storage's ImageProcessing transformer doesn't support :combine_options,
42
+ as it always generates a single command.
57
43
  ERROR
58
44
  end
59
-
60
- if argument.present?
61
- if argument.is_a?(String) || argument.is_a?(Symbol)
62
- validate_arg_string(argument)
63
- elsif argument.is_a?(Array)
64
- validate_arg_array(argument)
65
- elsif argument.is_a?(Hash)
66
- validate_arg_hash(argument)
67
- end
68
- end
69
- end
70
-
71
- def validate_arg_string(argument)
72
- unsupported_arguments = ActiveStorage.unsupported_image_processing_arguments.any? do |bad_arg|
73
- argument.to_s.downcase.include?(bad_arg)
74
- end
75
-
76
- raise UnsupportedImageProcessingArgument if unsupported_arguments
77
- end
78
-
79
- def validate_arg_array(argument)
80
- argument.each do |arg|
81
- if arg.is_a?(Integer) || arg.is_a?(Float)
82
- next
83
- elsif arg.is_a?(String) || arg.is_a?(Symbol)
84
- validate_arg_string(arg)
85
- elsif arg.is_a?(Array)
86
- validate_arg_array(arg)
87
- elsif arg.is_a?(Hash)
88
- validate_arg_hash(arg)
89
- end
90
- end
91
- end
92
-
93
- def validate_arg_hash(argument)
94
- argument.each do |key, value|
95
- validate_arg_string(key)
96
-
97
- if value.is_a?(Integer) || value.is_a?(Float)
98
- next
99
- elsif value.is_a?(String) || value.is_a?(Symbol)
100
- validate_arg_string(value)
101
- elsif value.is_a?(Array)
102
- validate_arg_array(value)
103
- elsif value.is_a?(Hash)
104
- validate_arg_hash(value)
105
- end
106
- end
107
45
  end
108
46
  end
109
47
  end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveStorage
4
+ module Transformers
5
+ class NullTransformer < Transformer # :nodoc:
6
+ private
7
+ def process(file, format:)
8
+ file
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveStorage
4
+ module Transformers
5
+ class Vips < ImageProcessingTransformer
6
+ def processor
7
+ ImageProcessing::Vips
8
+ end
9
+ end
10
+ end
11
+ end
@@ -27,6 +27,7 @@ require "active_record"
27
27
  require "active_support"
28
28
  require "active_support/rails"
29
29
  require "active_support/core_ext/numeric/time"
30
+ require "active_support/core_ext/numeric/bytes"
30
31
 
31
32
  require "active_storage/version"
32
33
  require "active_storage/deprecator"
@@ -49,6 +50,8 @@ module ActiveStorage
49
50
  mattr_accessor :verifier
50
51
  mattr_accessor :variant_processor, default: :mini_magick
51
52
 
53
+ mattr_accessor :variant_transformer
54
+
52
55
  mattr_accessor :queues, default: {}
53
56
 
54
57
  mattr_accessor :previewers, default: []
@@ -72,7 +75,6 @@ module ActiveStorage
72
75
  "annotate",
73
76
  "antialias",
74
77
  "append",
75
- "apply",
76
78
  "attenuate",
77
79
  "authenticate",
78
80
  "auto_gamma",
@@ -213,7 +215,6 @@ module ActiveStorage
213
215
  "linewidth",
214
216
  "liquid_rescale",
215
217
  "list",
216
- "loader",
217
218
  "log",
218
219
  "loop",
219
220
  "lowlight_color",
@@ -276,7 +277,6 @@ module ActiveStorage
276
277
  "rotate",
277
278
  "sample",
278
279
  "sampling_factor",
279
- "saver",
280
280
  "scale",
281
281
  "scene",
282
282
  "screen",
@@ -353,6 +353,7 @@ module ActiveStorage
353
353
  ]
354
354
  mattr_accessor :unsupported_image_processing_arguments
355
355
 
356
+ mattr_accessor :streaming_chunk_max_size, default: 100.megabytes
356
357
  mattr_accessor :service_urls_expire_in, default: 5.minutes
357
358
  mattr_accessor :touch_attachment_records, default: true
358
359
  mattr_accessor :urls_expire_in
@@ -363,12 +364,27 @@ module ActiveStorage
363
364
 
364
365
  mattr_accessor :track_variants, default: false
365
366
 
367
+ singleton_class.attr_accessor :checksum_implementation
368
+ @checksum_implementation = OpenSSL::Digest::MD5
369
+ begin
370
+ @checksum_implementation.hexdigest("test")
371
+ rescue # OpenSSL may have MD5 disabled
372
+ require "digest/md5"
373
+ @checksum_implementation = Digest::MD5
374
+ end
375
+
376
+ singleton_class.attr_accessor :streaming_max_ranges
377
+ @streaming_max_ranges = 1
378
+
366
379
  mattr_accessor :video_preview_arguments, default: "-y -vframes 1 -f image2"
367
380
 
368
381
  module Transformers
369
382
  extend ActiveSupport::Autoload
370
383
 
371
384
  autoload :Transformer
385
+ autoload :NullTransformer
372
386
  autoload :ImageProcessingTransformer
387
+ autoload :Vips
388
+ autoload :ImageMagick
373
389
  end
374
390
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activestorage
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.2.2.1
4
+ version: 8.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Heinemeier Hansson
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2024-12-10 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: activesupport
@@ -16,56 +15,56 @@ dependencies:
16
15
  requirements:
17
16
  - - '='
18
17
  - !ruby/object:Gem::Version
19
- version: 7.2.2.1
18
+ version: 8.1.3
20
19
  type: :runtime
21
20
  prerelease: false
22
21
  version_requirements: !ruby/object:Gem::Requirement
23
22
  requirements:
24
23
  - - '='
25
24
  - !ruby/object:Gem::Version
26
- version: 7.2.2.1
25
+ version: 8.1.3
27
26
  - !ruby/object:Gem::Dependency
28
27
  name: actionpack
29
28
  requirement: !ruby/object:Gem::Requirement
30
29
  requirements:
31
30
  - - '='
32
31
  - !ruby/object:Gem::Version
33
- version: 7.2.2.1
32
+ version: 8.1.3
34
33
  type: :runtime
35
34
  prerelease: false
36
35
  version_requirements: !ruby/object:Gem::Requirement
37
36
  requirements:
38
37
  - - '='
39
38
  - !ruby/object:Gem::Version
40
- version: 7.2.2.1
39
+ version: 8.1.3
41
40
  - !ruby/object:Gem::Dependency
42
41
  name: activejob
43
42
  requirement: !ruby/object:Gem::Requirement
44
43
  requirements:
45
44
  - - '='
46
45
  - !ruby/object:Gem::Version
47
- version: 7.2.2.1
46
+ version: 8.1.3
48
47
  type: :runtime
49
48
  prerelease: false
50
49
  version_requirements: !ruby/object:Gem::Requirement
51
50
  requirements:
52
51
  - - '='
53
52
  - !ruby/object:Gem::Version
54
- version: 7.2.2.1
53
+ version: 8.1.3
55
54
  - !ruby/object:Gem::Dependency
56
55
  name: activerecord
57
56
  requirement: !ruby/object:Gem::Requirement
58
57
  requirements:
59
58
  - - '='
60
59
  - !ruby/object:Gem::Version
61
- version: 7.2.2.1
60
+ version: 8.1.3
62
61
  type: :runtime
63
62
  prerelease: false
64
63
  version_requirements: !ruby/object:Gem::Requirement
65
64
  requirements:
66
65
  - - '='
67
66
  - !ruby/object:Gem::Version
68
- version: 7.2.2.1
67
+ version: 8.1.3
69
68
  - !ruby/object:Gem::Dependency
70
69
  name: marcel
71
70
  requirement: !ruby/object:Gem::Requirement
@@ -174,15 +173,18 @@ files:
174
173
  - lib/active_storage/previewer/video_previewer.rb
175
174
  - lib/active_storage/reflection.rb
176
175
  - lib/active_storage/service.rb
177
- - lib/active_storage/service/azure_storage_service.rb
178
176
  - lib/active_storage/service/configurator.rb
179
177
  - lib/active_storage/service/disk_service.rb
180
178
  - lib/active_storage/service/gcs_service.rb
181
179
  - lib/active_storage/service/mirror_service.rb
182
180
  - lib/active_storage/service/registry.rb
183
181
  - lib/active_storage/service/s3_service.rb
182
+ - lib/active_storage/structured_event_subscriber.rb
183
+ - lib/active_storage/transformers/image_magick.rb
184
184
  - lib/active_storage/transformers/image_processing_transformer.rb
185
+ - lib/active_storage/transformers/null_transformer.rb
185
186
  - lib/active_storage/transformers/transformer.rb
187
+ - lib/active_storage/transformers/vips.rb
186
188
  - lib/active_storage/version.rb
187
189
  - lib/tasks/activestorage.rake
188
190
  homepage: https://rubyonrails.org
@@ -190,12 +192,11 @@ licenses:
190
192
  - MIT
191
193
  metadata:
192
194
  bug_tracker_uri: https://github.com/rails/rails/issues
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
+ changelog_uri: https://github.com/rails/rails/blob/v8.1.3/activestorage/CHANGELOG.md
196
+ documentation_uri: https://api.rubyonrails.org/v8.1.3/
195
197
  mailing_list_uri: https://discuss.rubyonrails.org/c/rubyonrails-talk
196
- source_code_uri: https://github.com/rails/rails/tree/v7.2.2.1/activestorage
198
+ source_code_uri: https://github.com/rails/rails/tree/v8.1.3/activestorage
197
199
  rubygems_mfa_required: 'true'
198
- post_install_message:
199
200
  rdoc_options: []
200
201
  require_paths:
201
202
  - lib
@@ -203,15 +204,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
203
204
  requirements:
204
205
  - - ">="
205
206
  - !ruby/object:Gem::Version
206
- version: 3.1.0
207
+ version: 3.2.0
207
208
  required_rubygems_version: !ruby/object:Gem::Requirement
208
209
  requirements:
209
210
  - - ">="
210
211
  - !ruby/object:Gem::Version
211
212
  version: '0'
212
213
  requirements: []
213
- rubygems_version: 3.5.22
214
- signing_key:
214
+ rubygems_version: 4.0.6
215
215
  specification_version: 4
216
216
  summary: Local and cloud file storage framework.
217
217
  test_files: []