activestorage 6.1.6.1 → 7.0.3.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


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

Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +180 -212
  3. data/README.md +25 -11
  4. data/app/assets/javascripts/activestorage.esm.js +844 -0
  5. data/app/assets/javascripts/activestorage.js +257 -376
  6. data/app/controllers/active_storage/base_controller.rb +0 -9
  7. data/app/controllers/active_storage/blobs/proxy_controller.rb +15 -4
  8. data/app/controllers/active_storage/blobs/redirect_controller.rb +6 -4
  9. data/app/controllers/active_storage/disk_controller.rb +1 -0
  10. data/app/controllers/active_storage/representations/base_controller.rb +5 -1
  11. data/app/controllers/active_storage/representations/proxy_controller.rb +7 -3
  12. data/app/controllers/active_storage/representations/redirect_controller.rb +6 -4
  13. data/app/controllers/concerns/active_storage/set_blob.rb +6 -2
  14. data/app/controllers/concerns/active_storage/set_current.rb +3 -3
  15. data/app/controllers/concerns/active_storage/streaming.rb +65 -0
  16. data/app/javascript/activestorage/ujs.js +1 -1
  17. data/app/models/active_storage/attachment.rb +35 -2
  18. data/app/models/active_storage/blob/representable.rb +7 -5
  19. data/app/models/active_storage/blob.rb +92 -36
  20. data/app/models/active_storage/current.rb +12 -2
  21. data/app/models/active_storage/preview.rb +6 -4
  22. data/app/models/active_storage/record.rb +1 -1
  23. data/app/models/active_storage/variant.rb +3 -6
  24. data/app/models/active_storage/variant_record.rb +2 -0
  25. data/app/models/active_storage/variant_with_record.rb +9 -5
  26. data/app/models/active_storage/variation.rb +2 -2
  27. data/config/routes.rb +10 -10
  28. data/db/migrate/20170806125915_create_active_storage_tables.rb +32 -11
  29. data/db/update_migrate/20190112182829_add_service_name_to_active_storage_blobs.rb +4 -0
  30. data/db/update_migrate/20191206030411_create_active_storage_variant_records.rb +17 -2
  31. data/db/update_migrate/20211119233751_remove_not_null_on_active_storage_blobs_checksum.rb +7 -0
  32. data/lib/active_storage/analyzer/audio_analyzer.rb +65 -0
  33. data/lib/active_storage/analyzer/image_analyzer/image_magick.rb +39 -0
  34. data/lib/active_storage/analyzer/image_analyzer/vips.rb +49 -0
  35. data/lib/active_storage/analyzer/image_analyzer.rb +2 -30
  36. data/lib/active_storage/analyzer/video_analyzer.rb +27 -12
  37. data/lib/active_storage/analyzer.rb +8 -4
  38. data/lib/active_storage/attached/changes/create_many.rb +7 -3
  39. data/lib/active_storage/attached/changes/create_one.rb +1 -1
  40. data/lib/active_storage/attached/changes/create_one_of_many.rb +1 -1
  41. data/lib/active_storage/attached/changes/delete_many.rb +1 -1
  42. data/lib/active_storage/attached/changes/delete_one.rb +1 -1
  43. data/lib/active_storage/attached/changes/detach_many.rb +18 -0
  44. data/lib/active_storage/attached/changes/detach_one.rb +24 -0
  45. data/lib/active_storage/attached/changes/purge_many.rb +27 -0
  46. data/lib/active_storage/attached/changes/purge_one.rb +27 -0
  47. data/lib/active_storage/attached/changes.rb +7 -1
  48. data/lib/active_storage/attached/many.rb +27 -15
  49. data/lib/active_storage/attached/model.rb +35 -7
  50. data/lib/active_storage/attached/one.rb +32 -27
  51. data/lib/active_storage/downloader.rb +4 -4
  52. data/lib/active_storage/engine.rb +45 -1
  53. data/lib/active_storage/fixture_set.rb +76 -0
  54. data/lib/active_storage/gem_version.rb +4 -4
  55. data/lib/active_storage/previewer.rb +4 -4
  56. data/lib/active_storage/reflection.rb +12 -2
  57. data/lib/active_storage/service/azure_storage_service.rb +28 -6
  58. data/lib/active_storage/service/configurator.rb +1 -1
  59. data/lib/active_storage/service/disk_service.rb +24 -19
  60. data/lib/active_storage/service/gcs_service.rb +109 -11
  61. data/lib/active_storage/service/mirror_service.rb +2 -2
  62. data/lib/active_storage/service/registry.rb +1 -1
  63. data/lib/active_storage/service/s3_service.rb +37 -15
  64. data/lib/active_storage/service.rb +13 -5
  65. data/lib/active_storage/transformers/image_processing_transformer.rb +1 -1
  66. data/lib/active_storage/transformers/transformer.rb +1 -1
  67. data/lib/active_storage/version.rb +1 -1
  68. data/lib/active_storage.rb +4 -0
  69. metadata +24 -14
  70. data/app/controllers/concerns/active_storage/set_headers.rb +0 -12
@@ -1,12 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveStorage
4
- class Attached::Changes::CreateMany #:nodoc:
4
+ class Attached::Changes::CreateMany # :nodoc:
5
5
  attr_reader :name, :record, :attachables
6
6
 
7
7
  def initialize(name, record, attachables)
8
8
  @name, @record, @attachables = name, record, Array(attachables)
9
9
  blobs.each(&:identify_without_saving)
10
+ attachments
10
11
  end
11
12
 
12
13
  def attachments
@@ -35,13 +36,16 @@ module ActiveStorage
35
36
  ActiveStorage::Attached::Changes::CreateOneOfMany.new(name, record, attachable)
36
37
  end
37
38
 
38
-
39
39
  def assign_associated_attachments
40
- record.public_send("#{name}_attachments=", attachments)
40
+ record.public_send("#{name}_attachments=", persisted_or_new_attachments)
41
41
  end
42
42
 
43
43
  def reset_associated_blobs
44
44
  record.public_send("#{name}_blobs").reset
45
45
  end
46
+
47
+ def persisted_or_new_attachments
48
+ attachments.select { |attachment| attachment.persisted? || attachment.new_record? }
49
+ end
46
50
  end
47
51
  end
@@ -4,7 +4,7 @@ require "action_dispatch"
4
4
  require "action_dispatch/http/upload"
5
5
 
6
6
  module ActiveStorage
7
- class Attached::Changes::CreateOne #:nodoc:
7
+ class Attached::Changes::CreateOne # :nodoc:
8
8
  attr_reader :name, :record, :attachable
9
9
 
10
10
  def initialize(name, record, attachable)
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveStorage
4
- class Attached::Changes::CreateOneOfMany < Attached::Changes::CreateOne #:nodoc:
4
+ class Attached::Changes::CreateOneOfMany < Attached::Changes::CreateOne # :nodoc:
5
5
  private
6
6
  def find_attachment
7
7
  record.public_send("#{name}_attachments").detect { |attachment| attachment.blob_id == blob.id }
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveStorage
4
- class Attached::Changes::DeleteMany #:nodoc:
4
+ class Attached::Changes::DeleteMany # :nodoc:
5
5
  attr_reader :name, :record
6
6
 
7
7
  def initialize(name, record)
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveStorage
4
- class Attached::Changes::DeleteOne #:nodoc:
4
+ class Attached::Changes::DeleteOne # :nodoc:
5
5
  attr_reader :name, :record
6
6
 
7
7
  def initialize(name, record)
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveStorage
4
+ class Attached::Changes::DetachMany # :nodoc:
5
+ attr_reader :name, :record, :attachments
6
+
7
+ def initialize(name, record, attachments)
8
+ @name, @record, @attachments = name, record, attachments
9
+ end
10
+
11
+ def detach
12
+ if attachments.any?
13
+ attachments.delete_all if attachments.respond_to?(:delete_all)
14
+ record.attachment_changes.delete(name)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveStorage
4
+ class Attached::Changes::DetachOne # :nodoc:
5
+ attr_reader :name, :record, :attachment
6
+
7
+ def initialize(name, record, attachment)
8
+ @name, @record, @attachment = name, record, attachment
9
+ end
10
+
11
+ def detach
12
+ if attachment.present?
13
+ attachment.delete
14
+ reset
15
+ end
16
+ end
17
+
18
+ private
19
+ def reset
20
+ record.attachment_changes.delete(name)
21
+ record.public_send("#{name}_attachment=", nil)
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveStorage
4
+ class Attached::Changes::PurgeMany # :nodoc:
5
+ attr_reader :name, :record, :attachments
6
+
7
+ def initialize(name, record, attachments)
8
+ @name, @record, @attachments = name, record, attachments
9
+ end
10
+
11
+ def purge
12
+ attachments.each(&:purge)
13
+ reset
14
+ end
15
+
16
+ def purge_later
17
+ attachments.each(&:purge_later)
18
+ reset
19
+ end
20
+
21
+ private
22
+ def reset
23
+ record.attachment_changes.delete(name)
24
+ record.public_send("#{name}_attachments").reset
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveStorage
4
+ class Attached::Changes::PurgeOne # :nodoc:
5
+ attr_reader :name, :record, :attachment
6
+
7
+ def initialize(name, record, attachment)
8
+ @name, @record, @attachment = name, record, attachment
9
+ end
10
+
11
+ def purge
12
+ attachment&.purge
13
+ reset
14
+ end
15
+
16
+ def purge_later
17
+ attachment&.purge_later
18
+ reset
19
+ end
20
+
21
+ private
22
+ def reset
23
+ record.attachment_changes.delete(name)
24
+ record.public_send("#{name}_attachment=", nil)
25
+ end
26
+ end
27
+ end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveStorage
4
- module Attached::Changes #:nodoc:
4
+ module Attached::Changes # :nodoc:
5
5
  extend ActiveSupport::Autoload
6
6
 
7
7
  eager_autoload do
@@ -11,6 +11,12 @@ module ActiveStorage
11
11
 
12
12
  autoload :DeleteOne
13
13
  autoload :DeleteMany
14
+
15
+ autoload :DetachOne
16
+ autoload :DetachMany
17
+
18
+ autoload :PurgeOne
19
+ autoload :PurgeMany
14
20
  end
15
21
  end
16
22
  end
@@ -3,6 +3,25 @@
3
3
  module ActiveStorage
4
4
  # Decorated proxy object representing of multiple attachments to a model.
5
5
  class Attached::Many < Attached
6
+ ##
7
+ # :method: purge
8
+ #
9
+ # Directly purges each associated attachment (i.e. destroys the blobs and
10
+ # attachments and deletes the files on the service).
11
+ delegate :purge, to: :purge_many
12
+
13
+ ##
14
+ # :method: purge_later
15
+ #
16
+ # Purges each associated attachment through the queuing system.
17
+ delegate :purge_later, to: :purge_many
18
+
19
+ ##
20
+ # :method: detach
21
+ #
22
+ # Deletes associated attachments without purging them, leaving their respective blobs in place.
23
+ delegate :detach, to: :detach_many
24
+
6
25
  delegate_missing_to :attachments
7
26
 
8
27
  # Returns all the associated attachment records.
@@ -25,7 +44,7 @@ module ActiveStorage
25
44
  #
26
45
  # document.images.attach(params[:images]) # Array of ActionDispatch::Http::UploadedFile objects
27
46
  # document.images.attach(params[:signed_blob_id]) # Signed reference to blob from direct upload
28
- # document.images.attach(io: File.open("/path/to/racecar.jpg"), filename: "racecar.jpg", content_type: "image/jpg")
47
+ # document.images.attach(io: File.open("/path/to/racecar.jpg"), filename: "racecar.jpg", content_type: "image/jpeg")
29
48
  # document.images.attach([ first_blob, second_blob ])
30
49
  def attach(*attachables)
31
50
  if record.persisted? && !record.changed?
@@ -47,20 +66,13 @@ module ActiveStorage
47
66
  attachments.any?
48
67
  end
49
68
 
50
- # Deletes associated attachments without purging them, leaving their respective blobs in place.
51
- def detach
52
- attachments.delete_all if attached?
53
- end
54
-
55
- ##
56
- # :method: purge
57
- #
58
- # Directly purges each associated attachment (i.e. destroys the blobs and
59
- # attachments and deletes the files on the service).
69
+ private
70
+ def purge_many
71
+ Attached::Changes::PurgeMany.new(name, record, attachments)
72
+ end
60
73
 
61
- ##
62
- # :method: purge_later
63
- #
64
- # Purges each associated attachment through the queuing system.
74
+ def detach_many
75
+ Attached::Changes::DetachMany.new(name, record, attachments)
76
+ end
65
77
  end
66
78
  end
@@ -83,6 +83,7 @@ module ActiveStorage
83
83
  { dependent: dependent, service_name: service },
84
84
  self
85
85
  )
86
+ yield reflection if block_given?
86
87
  ActiveRecord::Reflection.add_attachment_reflection(self, name, reflection)
87
88
  end
88
89
 
@@ -136,15 +137,23 @@ module ActiveStorage
136
137
  end
137
138
 
138
139
  def #{name}=(attachables)
140
+ attachables = Array(attachables).compact_blank
141
+
139
142
  if ActiveStorage.replace_on_assign_to_many
140
143
  attachment_changes["#{name}"] =
141
- if Array(attachables).none?
144
+ if attachables.none?
142
145
  ActiveStorage::Attached::Changes::DeleteMany.new("#{name}", self)
143
146
  else
144
147
  ActiveStorage::Attached::Changes::CreateMany.new("#{name}", self, attachables)
145
148
  end
146
149
  else
147
- if Array(attachables).any?
150
+ ActiveSupport::Deprecation.warn \
151
+ "config.active_storage.replace_on_assign_to_many is deprecated and will be removed in Rails 7.1. " \
152
+ "Make sure that your code works well with config.active_storage.replace_on_assign_to_many set to true before upgrading. " \
153
+ "To append new attachables to the Active Storage association, prefer using `attach`. " \
154
+ "Using association setter would result in purging the existing attached attachments and replacing them with new ones."
155
+
156
+ if attachables.any?
148
157
  attachment_changes["#{name}"] =
149
158
  ActiveStorage::Attached::Changes::CreateMany.new("#{name}", self, #{name}.blobs + attachables)
150
159
  end
@@ -154,18 +163,36 @@ module ActiveStorage
154
163
 
155
164
  has_many :"#{name}_attachments", -> { where(name: name) }, as: :record, class_name: "ActiveStorage::Attachment", inverse_of: :record, dependent: :destroy, strict_loading: strict_loading do
156
165
  def purge
166
+ deprecate(:purge)
157
167
  each(&:purge)
158
168
  reset
159
169
  end
160
170
 
161
171
  def purge_later
172
+ deprecate(:purge_later)
162
173
  each(&:purge_later)
163
174
  reset
164
175
  end
176
+
177
+ private
178
+ def deprecate(action)
179
+ reflection_name = proxy_association.reflection.name
180
+ attached_name = reflection_name.to_s.partition("_").first
181
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
182
+ Calling `#{action}` from `#{reflection_name}` is deprecated and will be removed in Rails 7.1.
183
+ To migrate to Rails 7.1's behavior call `#{action}` from `#{attached_name}` instead: `#{attached_name}.#{action}`.
184
+ MSG
185
+ end
165
186
  end
166
187
  has_many :"#{name}_blobs", through: :"#{name}_attachments", class_name: "ActiveStorage::Blob", source: :blob, strict_loading: strict_loading
167
188
 
168
- scope :"with_attached_#{name}", -> { includes("#{name}_attachments": :blob) }
189
+ scope :"with_attached_#{name}", -> {
190
+ if ActiveStorage.track_variants
191
+ includes("#{name}_attachments": { blob: :variant_records })
192
+ else
193
+ includes("#{name}_attachments": :blob)
194
+ end
195
+ }
169
196
 
170
197
  after_save { attachment_changes[name.to_s]&.save }
171
198
 
@@ -178,6 +205,7 @@ module ActiveStorage
178
205
  { dependent: dependent, service_name: service },
179
206
  self
180
207
  )
208
+ yield reflection if block_given?
181
209
  ActiveRecord::Reflection.add_attachment_reflection(self, name, reflection)
182
210
  end
183
211
 
@@ -191,21 +219,21 @@ module ActiveStorage
191
219
  end
192
220
  end
193
221
 
194
- def attachment_changes #:nodoc:
222
+ def attachment_changes # :nodoc:
195
223
  @attachment_changes ||= {}
196
224
  end
197
225
 
198
- def changed_for_autosave? #:nodoc:
226
+ def changed_for_autosave? # :nodoc:
199
227
  super || attachment_changes.any?
200
228
  end
201
229
 
202
- def initialize_dup(*) #:nodoc:
230
+ def initialize_dup(*) # :nodoc:
203
231
  super
204
232
  @active_storage_attached = nil
205
233
  @attachment_changes = nil
206
234
  end
207
235
 
208
- def reload(*) #:nodoc:
236
+ def reload(*) # :nodoc:
209
237
  super.tap { @attachment_changes = nil }
210
238
  end
211
239
  end
@@ -3,6 +3,25 @@
3
3
  module ActiveStorage
4
4
  # Representation of a single attachment to a model.
5
5
  class Attached::One < Attached
6
+ ##
7
+ # :method: purge
8
+ #
9
+ # Directly purges the attachment (i.e. destroys the blob and
10
+ # attachment and deletes the file on the service).
11
+ delegate :purge, to: :purge_one
12
+
13
+ ##
14
+ # :method: purge_later
15
+ #
16
+ # Purges the attachment through the queuing system.
17
+ delegate :purge_later, to: :purge_one
18
+
19
+ ##
20
+ # :method: detach
21
+ #
22
+ # Deletes the attachment without purging it, leaving its blob in place.
23
+ delegate :detach, to: :detach_one
24
+
6
25
  delegate_missing_to :attachment, allow_nil: true
7
26
 
8
27
  # Returns the associated attachment record.
@@ -13,6 +32,13 @@ module ActiveStorage
13
32
  change.present? ? change.attachment : record.public_send("#{name}_attachment")
14
33
  end
15
34
 
35
+ # Returns +true+ if an attachment is not attached.
36
+ #
37
+ # class User < ApplicationRecord
38
+ # has_one_attached :avatar
39
+ # end
40
+ #
41
+ # User.new.avatar.blank? # => true
16
42
  def blank?
17
43
  !attached?
18
44
  end
@@ -25,7 +51,7 @@ module ActiveStorage
25
51
  #
26
52
  # person.avatar.attach(params[:avatar]) # ActionDispatch::Http::UploadedFile object
27
53
  # person.avatar.attach(params[:signed_blob_id]) # Signed reference to blob from direct upload
28
- # person.avatar.attach(io: File.open("/path/to/face.jpg"), filename: "face.jpg", content_type: "image/jpg")
54
+ # person.avatar.attach(io: File.open("/path/to/face.jpg"), filename: "face.jpg", content_type: "image/jpeg")
29
55
  # person.avatar.attach(avatar_blob) # ActiveStorage::Blob object
30
56
  def attach(attachable)
31
57
  if record.persisted? && !record.changed?
@@ -47,34 +73,13 @@ module ActiveStorage
47
73
  attachment.present?
48
74
  end
49
75
 
50
- # Deletes the attachment without purging it, leaving its blob in place.
51
- def detach
52
- if attached?
53
- attachment.delete
54
- write_attachment nil
55
- end
56
- end
57
-
58
- # Directly purges the attachment (i.e. destroys the blob and
59
- # attachment and deletes the file on the service).
60
- def purge
61
- if attached?
62
- attachment.purge
63
- write_attachment nil
64
- end
65
- end
66
-
67
- # Purges the attachment through the queuing system.
68
- def purge_later
69
- if attached?
70
- attachment.purge_later
71
- write_attachment nil
76
+ private
77
+ def purge_one
78
+ Attached::Changes::PurgeOne.new(name, record, attachment)
72
79
  end
73
- end
74
80
 
75
- private
76
- def write_attachment(attachment)
77
- record.public_send("#{name}_attachment=", attachment)
81
+ def detach_one
82
+ Attached::Changes::DetachOne.new(name, record, attachment)
78
83
  end
79
84
  end
80
85
  end
@@ -1,17 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveStorage
4
- class Downloader #:nodoc:
4
+ class Downloader # :nodoc:
5
5
  attr_reader :service
6
6
 
7
7
  def initialize(service)
8
8
  @service = service
9
9
  end
10
10
 
11
- def open(key, checksum:, name: "ActiveStorage-", tmpdir: nil)
11
+ def open(key, checksum: nil, verify: true, name: "ActiveStorage-", tmpdir: nil)
12
12
  open_tempfile(name, tmpdir) do |file|
13
13
  download key, file
14
- verify_integrity_of file, checksum: checksum
14
+ verify_integrity_of(file, checksum: checksum) if verify
15
15
  yield file
16
16
  end
17
17
  end
@@ -35,7 +35,7 @@ module ActiveStorage
35
35
  end
36
36
 
37
37
  def verify_integrity_of(file, checksum:)
38
- unless Digest::MD5.file(file).base64digest == checksum
38
+ unless OpenSSL::Digest::MD5.file(file).base64digest == checksum
39
39
  raise ActiveStorage::IntegrityError
40
40
  end
41
41
  end
@@ -12,7 +12,10 @@ require "active_storage/previewer/mupdf_previewer"
12
12
  require "active_storage/previewer/video_previewer"
13
13
 
14
14
  require "active_storage/analyzer/image_analyzer"
15
+ require "active_storage/analyzer/image_analyzer/image_magick"
16
+ require "active_storage/analyzer/image_analyzer/vips"
15
17
  require "active_storage/analyzer/video_analyzer"
18
+ require "active_storage/analyzer/audio_analyzer"
16
19
 
17
20
  require "active_storage/service/registry"
18
21
 
@@ -24,9 +27,10 @@ module ActiveStorage
24
27
 
25
28
  config.active_storage = ActiveSupport::OrderedOptions.new
26
29
  config.active_storage.previewers = [ ActiveStorage::Previewer::PopplerPDFPreviewer, ActiveStorage::Previewer::MuPDFPreviewer, ActiveStorage::Previewer::VideoPreviewer ]
27
- config.active_storage.analyzers = [ ActiveStorage::Analyzer::ImageAnalyzer, ActiveStorage::Analyzer::VideoAnalyzer ]
30
+ config.active_storage.analyzers = [ ActiveStorage::Analyzer::ImageAnalyzer::Vips, ActiveStorage::Analyzer::ImageAnalyzer::ImageMagick, ActiveStorage::Analyzer::VideoAnalyzer, ActiveStorage::Analyzer::AudioAnalyzer ]
28
31
  config.active_storage.paths = ActiveSupport::OrderedOptions.new
29
32
  config.active_storage.queues = ActiveSupport::InheritableOptions.new
33
+ config.active_storage.precompile_assets = true
30
34
 
31
35
  config.active_storage.variable_content_types = %w(
32
36
  image/png
@@ -39,6 +43,9 @@ module ActiveStorage
39
43
  image/vnd.adobe.photoshop
40
44
  image/vnd.microsoft.icon
41
45
  image/webp
46
+ image/avif
47
+ image/heic
48
+ image/heif
42
49
  )
43
50
 
44
51
  config.active_storage.web_image_content_types = %w(
@@ -105,10 +112,13 @@ module ActiveStorage
105
112
  ActiveStorage.web_image_content_types = app.config.active_storage.web_image_content_types || []
106
113
  ActiveStorage.content_types_to_serve_as_binary = app.config.active_storage.content_types_to_serve_as_binary || []
107
114
  ActiveStorage.service_urls_expire_in = app.config.active_storage.service_urls_expire_in || 5.minutes
115
+ ActiveStorage.urls_expire_in = app.config.active_storage.urls_expire_in
108
116
  ActiveStorage.content_types_allowed_inline = app.config.active_storage.content_types_allowed_inline || []
109
117
  ActiveStorage.binary_content_type = app.config.active_storage.binary_content_type || "application/octet-stream"
110
118
  ActiveStorage.video_preview_arguments = app.config.active_storage.video_preview_arguments || "-y -vframes 1 -f image2"
111
119
 
120
+ ActiveStorage.silence_invalid_content_types_warning = app.config.active_storage.silence_invalid_content_types_warning || false
121
+
112
122
  ActiveStorage.replace_on_assign_to_many = app.config.active_storage.replace_on_assign_to_many || false
113
123
  ActiveStorage.track_variants = app.config.active_storage.track_variants || false
114
124
  end
@@ -159,5 +169,39 @@ module ActiveStorage
159
169
  ActiveRecord::Reflection.singleton_class.prepend(Reflection::ReflectionExtension)
160
170
  end
161
171
  end
172
+
173
+ initializer "action_view.configuration" do
174
+ config.after_initialize do |app|
175
+ ActiveSupport.on_load(:action_view) do
176
+ multiple_file_field_include_hidden = app.config.active_storage.delete(:multiple_file_field_include_hidden)
177
+
178
+ unless multiple_file_field_include_hidden.nil?
179
+ ActionView::Helpers::FormHelper.multiple_file_field_include_hidden = multiple_file_field_include_hidden
180
+ end
181
+ end
182
+ end
183
+ end
184
+
185
+ initializer "active_storage.asset" do
186
+ config.after_initialize do |app|
187
+ if app.config.respond_to?(:assets) && app.config.active_storage.precompile_assets
188
+ app.config.assets.precompile += %w( activestorage activestorage.esm )
189
+ end
190
+ end
191
+ end
192
+
193
+ initializer "active_storage.fixture_set" do
194
+ ActiveSupport.on_load(:active_record_fixture_set) do
195
+ ActiveStorage::FixtureSet.file_fixture_path ||= Rails.root.join(*[
196
+ ENV.fetch("FIXTURES_PATH") { File.join("test", "fixtures") },
197
+ ENV["FIXTURES_DIR"],
198
+ "files"
199
+ ].compact_blank)
200
+ end
201
+
202
+ ActiveSupport.on_load(:active_support_test_case) do
203
+ ActiveStorage::FixtureSet.file_fixture_path = ActiveSupport::TestCase.file_fixture_path
204
+ end
205
+ end
162
206
  end
163
207
  end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/testing/file_fixtures"
4
+ require "active_record/secure_token"
5
+
6
+ module ActiveStorage
7
+ # Fixtures are a way of organizing data that you want to test against; in
8
+ # short, sample data.
9
+ #
10
+ # To learn more about fixtures, read the
11
+ # {ActiveRecord::FixtureSet}[rdoc-ref:ActiveRecord::FixtureSet] documentation.
12
+ #
13
+ # === YAML
14
+ #
15
+ # Like other Active Record-backed models,
16
+ # {ActiveStorage::Attachment}[rdoc-ref:ActiveStorage::Attachment] and
17
+ # {ActiveStorage::Blob}[rdoc-ref:ActiveStorage::Blob] records inherit from
18
+ # {ActiveRecord::Base}[rdoc-ref:ActiveRecord::Base] instances and therefore
19
+ # can be populated by fixtures.
20
+ #
21
+ # Consider a hypothetical <tt>Article</tt> model class, its related
22
+ # fixture data, as well as fixture data for related ActiveStorage::Attachment
23
+ # and ActiveStorage::Blob records:
24
+ #
25
+ # # app/models/article.rb
26
+ # class Article < ApplicationRecord
27
+ # has_one_attached :thumbnail
28
+ # end
29
+ #
30
+ # # fixtures/active_storage/blobs.yml
31
+ # first_thumbnail_blob: <%= ActiveStorage::FixtureSet.blob filename: "first.png" %>
32
+ #
33
+ # # fixtures/active_storage/attachments.yml
34
+ # first_thumbnail_attachment:
35
+ # name: thumbnail
36
+ # record: first (Article)
37
+ # blob: first_thumbnail_blob
38
+ #
39
+ # When processed, Active Record will insert database records for each fixture
40
+ # entry and will ensure the Active Storage relationship is intact.
41
+ class FixtureSet
42
+ include ActiveSupport::Testing::FileFixtures
43
+ include ActiveRecord::SecureToken
44
+
45
+ # Generate a YAML-encoded representation of an ActiveStorage::Blob
46
+ # instance's attributes, resolve the file relative to the directory mentioned
47
+ # by <tt>ActiveSupport::Testing::FileFixtures.file_fixture</tt>, and upload
48
+ # the file to the Service
49
+ #
50
+ # === Examples
51
+ #
52
+ # # tests/fixtures/action_text/blobs.yml
53
+ # second_thumbnail_blob: <%= ActiveStorage::FixtureSet.blob(
54
+ # filename: "second.svg",
55
+ # ) %>
56
+ #
57
+ # third_thumbnail_blob: <%= ActiveStorage::FixtureSet.blob(
58
+ # filename: "third.svg",
59
+ # content_type: "image/svg+xml",
60
+ # service_name: "public"
61
+ # ) %>
62
+ #
63
+ def self.blob(filename:, **attributes)
64
+ new.prepare Blob.new(filename: filename, key: generate_unique_secure_token), **attributes
65
+ end
66
+
67
+ def prepare(instance, **attributes)
68
+ io = file_fixture(instance.filename.to_s).open
69
+ instance.unfurl(io)
70
+ instance.assign_attributes(attributes)
71
+ instance.upload_without_unfurling(io)
72
+
73
+ instance.attributes.transform_values { |value| value.is_a?(Hash) ? value.to_json : value }.compact.to_json
74
+ end
75
+ end
76
+ end
@@ -1,15 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveStorage
4
- # Returns the version of the currently loaded Active Storage as a <tt>Gem::Version</tt>.
4
+ # Returns the currently loaded version of Active Storage as a <tt>Gem::Version</tt>.
5
5
  def self.gem_version
6
6
  Gem::Version.new VERSION::STRING
7
7
  end
8
8
 
9
9
  module VERSION
10
- MAJOR = 6
11
- MINOR = 1
12
- TINY = 6
10
+ MAJOR = 7
11
+ MINOR = 0
12
+ TINY = 3
13
13
  PRE = "1"
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")