activestorage 6.1.7 → 7.1.0

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 (85) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +152 -276
  3. data/MIT-LICENSE +1 -1
  4. data/README.md +29 -15
  5. data/app/assets/javascripts/activestorage.esm.js +848 -0
  6. data/app/assets/javascripts/activestorage.js +263 -376
  7. data/app/controllers/active_storage/base_controller.rb +0 -9
  8. data/app/controllers/active_storage/blobs/proxy_controller.rb +16 -4
  9. data/app/controllers/active_storage/blobs/redirect_controller.rb +6 -4
  10. data/app/controllers/active_storage/disk_controller.rb +5 -2
  11. data/app/controllers/active_storage/representations/base_controller.rb +5 -1
  12. data/app/controllers/active_storage/representations/proxy_controller.rb +8 -3
  13. data/app/controllers/active_storage/representations/redirect_controller.rb +6 -4
  14. data/app/controllers/concerns/active_storage/disable_session.rb +12 -0
  15. data/app/controllers/concerns/active_storage/file_server.rb +4 -1
  16. data/app/controllers/concerns/active_storage/set_blob.rb +6 -2
  17. data/app/controllers/concerns/active_storage/set_current.rb +3 -3
  18. data/app/controllers/concerns/active_storage/streaming.rb +66 -0
  19. data/app/javascript/activestorage/blob_record.js +4 -1
  20. data/app/javascript/activestorage/direct_upload.js +3 -2
  21. data/app/javascript/activestorage/index.js +3 -1
  22. data/app/javascript/activestorage/ujs.js +1 -1
  23. data/app/jobs/active_storage/analyze_job.rb +1 -1
  24. data/app/jobs/active_storage/mirror_job.rb +1 -1
  25. data/app/jobs/active_storage/purge_job.rb +1 -1
  26. data/app/jobs/active_storage/transform_job.rb +12 -0
  27. data/app/models/active_storage/attachment.rb +111 -4
  28. data/app/models/active_storage/blob/analyzable.rb +4 -3
  29. data/app/models/active_storage/blob/identifiable.rb +1 -0
  30. data/app/models/active_storage/blob/representable.rb +14 -8
  31. data/app/models/active_storage/blob.rb +93 -57
  32. data/app/models/active_storage/current.rb +2 -2
  33. data/app/models/active_storage/filename.rb +2 -0
  34. data/app/models/active_storage/named_variant.rb +21 -0
  35. data/app/models/active_storage/preview.rb +11 -7
  36. data/app/models/active_storage/record.rb +1 -1
  37. data/app/models/active_storage/variant.rb +10 -12
  38. data/app/models/active_storage/variant_record.rb +2 -0
  39. data/app/models/active_storage/variant_with_record.rb +28 -12
  40. data/app/models/active_storage/variation.rb +7 -5
  41. data/config/routes.rb +12 -10
  42. data/db/migrate/20170806125915_create_active_storage_tables.rb +15 -6
  43. data/db/update_migrate/20211119233751_remove_not_null_on_active_storage_blobs_checksum.rb +7 -0
  44. data/lib/active_storage/analyzer/audio_analyzer.rb +77 -0
  45. data/lib/active_storage/analyzer/image_analyzer/image_magick.rb +41 -0
  46. data/lib/active_storage/analyzer/image_analyzer/vips.rb +51 -0
  47. data/lib/active_storage/analyzer/image_analyzer.rb +4 -30
  48. data/lib/active_storage/analyzer/video_analyzer.rb +41 -17
  49. data/lib/active_storage/analyzer.rb +10 -4
  50. data/lib/active_storage/attached/changes/create_many.rb +14 -5
  51. data/lib/active_storage/attached/changes/create_one.rb +46 -4
  52. data/lib/active_storage/attached/changes/create_one_of_many.rb +1 -1
  53. data/lib/active_storage/attached/changes/delete_many.rb +1 -1
  54. data/lib/active_storage/attached/changes/delete_one.rb +1 -1
  55. data/lib/active_storage/attached/changes/detach_many.rb +18 -0
  56. data/lib/active_storage/attached/changes/detach_one.rb +24 -0
  57. data/lib/active_storage/attached/changes/purge_many.rb +27 -0
  58. data/lib/active_storage/attached/changes/purge_one.rb +27 -0
  59. data/lib/active_storage/attached/changes.rb +7 -1
  60. data/lib/active_storage/attached/many.rb +32 -19
  61. data/lib/active_storage/attached/model.rb +80 -29
  62. data/lib/active_storage/attached/one.rb +37 -31
  63. data/lib/active_storage/attached.rb +2 -0
  64. data/lib/active_storage/deprecator.rb +7 -0
  65. data/lib/active_storage/downloader.rb +4 -4
  66. data/lib/active_storage/engine.rb +55 -7
  67. data/lib/active_storage/fixture_set.rb +75 -0
  68. data/lib/active_storage/gem_version.rb +3 -3
  69. data/lib/active_storage/log_subscriber.rb +12 -0
  70. data/lib/active_storage/previewer.rb +12 -5
  71. data/lib/active_storage/reflection.rb +12 -2
  72. data/lib/active_storage/service/azure_storage_service.rb +30 -6
  73. data/lib/active_storage/service/configurator.rb +1 -1
  74. data/lib/active_storage/service/disk_service.rb +26 -19
  75. data/lib/active_storage/service/gcs_service.rb +100 -11
  76. data/lib/active_storage/service/mirror_service.rb +12 -7
  77. data/lib/active_storage/service/registry.rb +1 -1
  78. data/lib/active_storage/service/s3_service.rb +39 -15
  79. data/lib/active_storage/service.rb +17 -7
  80. data/lib/active_storage/transformers/image_processing_transformer.rb +1 -1
  81. data/lib/active_storage/transformers/transformer.rb +3 -1
  82. data/lib/active_storage/version.rb +1 -1
  83. data/lib/active_storage.rb +22 -2
  84. metadata +30 -30
  85. data/app/controllers/concerns/active_storage/set_headers.rb +0 -12
@@ -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
@@ -1,8 +1,29 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveStorage
4
+ # = Active Storage \Attached \Many
5
+ #
4
6
  # Decorated proxy object representing of multiple attachments to a model.
5
7
  class Attached::Many < Attached
8
+ ##
9
+ # :method: purge
10
+ #
11
+ # Directly purges each associated attachment (i.e. destroys the blobs and
12
+ # attachments and deletes the files on the service).
13
+ delegate :purge, to: :purge_many
14
+
15
+ ##
16
+ # :method: purge_later
17
+ #
18
+ # Purges each associated attachment through the queuing system.
19
+ delegate :purge_later, to: :purge_many
20
+
21
+ ##
22
+ # :method: detach
23
+ #
24
+ # Deletes associated attachments without purging them, leaving their respective blobs in place.
25
+ delegate :detach, to: :detach_many
26
+
6
27
  delegate_missing_to :attachments
7
28
 
8
29
  # Returns all the associated attachment records.
@@ -25,15 +46,14 @@ module ActiveStorage
25
46
  #
26
47
  # document.images.attach(params[:images]) # Array of ActionDispatch::Http::UploadedFile objects
27
48
  # 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")
49
+ # document.images.attach(io: File.open("/path/to/racecar.jpg"), filename: "racecar.jpg", content_type: "image/jpeg")
29
50
  # document.images.attach([ first_blob, second_blob ])
30
51
  def attach(*attachables)
52
+ record.public_send("#{name}=", blobs + attachables.flatten)
31
53
  if record.persisted? && !record.changed?
32
- record.public_send("#{name}=", blobs + attachables.flatten)
33
- record.save
34
- else
35
- record.public_send("#{name}=", (change&.attachables || blobs) + attachables.flatten)
54
+ return if !record.save
36
55
  end
56
+ record.public_send("#{name}")
37
57
  end
38
58
 
39
59
  # Returns true if any attachments have been made.
@@ -47,20 +67,13 @@ module ActiveStorage
47
67
  attachments.any?
48
68
  end
49
69
 
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).
70
+ private
71
+ def purge_many
72
+ Attached::Changes::PurgeMany.new(name, record, attachments)
73
+ end
60
74
 
61
- ##
62
- # :method: purge_later
63
- #
64
- # Purges each associated attachment through the queuing system.
75
+ def detach_many
76
+ Attached::Changes::DetachMany.new(name, record, attachments)
77
+ end
65
78
  end
66
79
  end
@@ -3,10 +3,54 @@
3
3
  require "active_support/core_ext/object/try"
4
4
 
5
5
  module ActiveStorage
6
+ # = Active Storage \Attached \Model
7
+ #
6
8
  # Provides the class-level DSL for declaring an Active Record model's attachments.
7
9
  module Attached::Model
8
10
  extend ActiveSupport::Concern
9
11
 
12
+ ##
13
+ # :method: *_attachment
14
+ #
15
+ # Returns the attachment for the +has_one_attached+.
16
+ #
17
+ # User.last.avatar_attachment
18
+
19
+ ##
20
+ # :method: *_attachments
21
+ #
22
+ # Returns the attachments for the +has_many_attached+.
23
+ #
24
+ # Gallery.last.photos_attachments
25
+
26
+ ##
27
+ # :method: *_blob
28
+ #
29
+ # Returns the blob for the +has_one_attached+ attachment.
30
+ #
31
+ # User.last.avatar_blob
32
+
33
+ ##
34
+ # :method: *_blobs
35
+ #
36
+ # Returns the blobs for the +has_many_attached+ attachments.
37
+ #
38
+ # Gallery.last.photos_blobs
39
+
40
+ ##
41
+ # :method: with_attached_*
42
+ #
43
+ # Includes the attached blobs in your query to avoid N+1 queries.
44
+ #
45
+ # If +ActiveStorage.track_variants+ is enabled, it will also include the
46
+ # variants record and their attached blobs.
47
+ #
48
+ # User.with_attached_avatar
49
+ #
50
+ # Use the plural form for +has_many_attached+:
51
+ #
52
+ # Gallery.with_attached_photos
53
+
10
54
  class_methods do
11
55
  # Specifies the relation between a single attachment and the model.
12
56
  #
@@ -59,7 +103,7 @@ module ActiveStorage
59
103
 
60
104
  def #{name}=(attachable)
61
105
  attachment_changes["#{name}"] =
62
- if attachable.nil?
106
+ if attachable.nil? || attachable == ""
63
107
  ActiveStorage::Attached::Changes::DeleteOne.new("#{name}", self)
64
108
  else
65
109
  ActiveStorage::Attached::Changes::CreateOne.new("#{name}", self, attachable)
@@ -70,7 +114,13 @@ module ActiveStorage
70
114
  has_one :"#{name}_attachment", -> { where(name: name) }, class_name: "ActiveStorage::Attachment", as: :record, inverse_of: :record, dependent: :destroy, strict_loading: strict_loading
71
115
  has_one :"#{name}_blob", through: :"#{name}_attachment", class_name: "ActiveStorage::Blob", source: :blob, strict_loading: strict_loading
72
116
 
73
- scope :"with_attached_#{name}", -> { includes("#{name}_attachment": :blob) }
117
+ scope :"with_attached_#{name}", -> {
118
+ if ActiveStorage.track_variants
119
+ includes("#{name}_attachment": { blob: { variant_records: { image_attachment: :blob } } })
120
+ else
121
+ includes("#{name}_attachment": :blob)
122
+ end
123
+ }
74
124
 
75
125
  after_save { attachment_changes[name.to_s]&.save }
76
126
 
@@ -83,6 +133,7 @@ module ActiveStorage
83
133
  { dependent: dependent, service_name: service },
84
134
  self
85
135
  )
136
+ yield reflection if block_given?
86
137
  ActiveRecord::Reflection.add_attachment_reflection(self, name, reflection)
87
138
  end
88
139
 
@@ -136,36 +187,27 @@ module ActiveStorage
136
187
  end
137
188
 
138
189
  def #{name}=(attachables)
139
- if ActiveStorage.replace_on_assign_to_many
140
- attachment_changes["#{name}"] =
141
- if Array(attachables).none?
142
- ActiveStorage::Attached::Changes::DeleteMany.new("#{name}", self)
143
- else
144
- ActiveStorage::Attached::Changes::CreateMany.new("#{name}", self, attachables)
145
- end
190
+ attachables = Array(attachables).compact_blank
191
+ pending_uploads = attachment_changes["#{name}"].try(:pending_uploads)
192
+
193
+ attachment_changes["#{name}"] = if attachables.none?
194
+ ActiveStorage::Attached::Changes::DeleteMany.new("#{name}", self)
146
195
  else
147
- if Array(attachables).any?
148
- attachment_changes["#{name}"] =
149
- ActiveStorage::Attached::Changes::CreateMany.new("#{name}", self, #{name}.blobs + attachables)
150
- end
196
+ ActiveStorage::Attached::Changes::CreateMany.new("#{name}", self, attachables, pending_uploads: pending_uploads)
151
197
  end
152
198
  end
153
199
  CODE
154
200
 
155
- has_many :"#{name}_attachments", -> { where(name: name) }, as: :record, class_name: "ActiveStorage::Attachment", inverse_of: :record, dependent: :destroy, strict_loading: strict_loading do
156
- def purge
157
- each(&:purge)
158
- reset
159
- end
160
-
161
- def purge_later
162
- each(&:purge_later)
163
- reset
164
- end
165
- end
201
+ has_many :"#{name}_attachments", -> { where(name: name) }, as: :record, class_name: "ActiveStorage::Attachment", inverse_of: :record, dependent: :destroy, strict_loading: strict_loading
166
202
  has_many :"#{name}_blobs", through: :"#{name}_attachments", class_name: "ActiveStorage::Blob", source: :blob, strict_loading: strict_loading
167
203
 
168
- scope :"with_attached_#{name}", -> { includes("#{name}_attachments": :blob) }
204
+ scope :"with_attached_#{name}", -> {
205
+ if ActiveStorage.track_variants
206
+ includes("#{name}_attachments": { blob: { variant_records: { image_attachment: :blob } } })
207
+ else
208
+ includes("#{name}_attachments": :blob)
209
+ end
210
+ }
169
211
 
170
212
  after_save { attachment_changes[name.to_s]&.save }
171
213
 
@@ -178,6 +220,7 @@ module ActiveStorage
178
220
  { dependent: dependent, service_name: service },
179
221
  self
180
222
  )
223
+ yield reflection if block_given?
181
224
  ActiveRecord::Reflection.add_attachment_reflection(self, name, reflection)
182
225
  end
183
226
 
@@ -187,25 +230,33 @@ module ActiveStorage
187
230
  ActiveStorage::Blob.services.fetch(service) do
188
231
  raise ArgumentError, "Cannot configure service :#{service} for #{name}##{association_name}"
189
232
  end
233
+ else
234
+ validate_global_service_configuration
235
+ end
236
+ end
237
+
238
+ def validate_global_service_configuration
239
+ if connected? && ActiveStorage::Blob.table_exists? && Rails.configuration.active_storage.service.nil?
240
+ raise RuntimeError, "Missing Active Storage service name. Specify Active Storage service name for config.active_storage.service in config/environments/#{Rails.env}.rb"
190
241
  end
191
242
  end
192
243
  end
193
244
 
194
- def attachment_changes #:nodoc:
245
+ def attachment_changes # :nodoc:
195
246
  @attachment_changes ||= {}
196
247
  end
197
248
 
198
- def changed_for_autosave? #:nodoc:
249
+ def changed_for_autosave? # :nodoc:
199
250
  super || attachment_changes.any?
200
251
  end
201
252
 
202
- def initialize_dup(*) #:nodoc:
253
+ def initialize_dup(*) # :nodoc:
203
254
  super
204
255
  @active_storage_attached = nil
205
256
  @attachment_changes = nil
206
257
  end
207
258
 
208
- def reload(*) #:nodoc:
259
+ def reload(*) # :nodoc:
209
260
  super.tap { @attachment_changes = nil }
210
261
  end
211
262
  end
@@ -1,8 +1,29 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveStorage
4
+ # = Active Storage \Attached \One
5
+ #
4
6
  # Representation of a single attachment to a model.
5
7
  class Attached::One < Attached
8
+ ##
9
+ # :method: purge
10
+ #
11
+ # Directly purges the attachment (i.e. destroys the blob and
12
+ # attachment and deletes the file on the service).
13
+ delegate :purge, to: :purge_one
14
+
15
+ ##
16
+ # :method: purge_later
17
+ #
18
+ # Purges the attachment through the queuing system.
19
+ delegate :purge_later, to: :purge_one
20
+
21
+ ##
22
+ # :method: detach
23
+ #
24
+ # Deletes the attachment without purging it, leaving its blob in place.
25
+ delegate :detach, to: :detach_one
26
+
6
27
  delegate_missing_to :attachment, allow_nil: true
7
28
 
8
29
  # Returns the associated attachment record.
@@ -13,6 +34,13 @@ module ActiveStorage
13
34
  change.present? ? change.attachment : record.public_send("#{name}_attachment")
14
35
  end
15
36
 
37
+ # Returns +true+ if an attachment is not attached.
38
+ #
39
+ # class User < ApplicationRecord
40
+ # has_one_attached :avatar
41
+ # end
42
+ #
43
+ # User.new.avatar.blank? # => true
16
44
  def blank?
17
45
  !attached?
18
46
  end
@@ -25,15 +53,14 @@ module ActiveStorage
25
53
  #
26
54
  # person.avatar.attach(params[:avatar]) # ActionDispatch::Http::UploadedFile object
27
55
  # 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")
56
+ # person.avatar.attach(io: File.open("/path/to/face.jpg"), filename: "face.jpg", content_type: "image/jpeg")
29
57
  # person.avatar.attach(avatar_blob) # ActiveStorage::Blob object
30
58
  def attach(attachable)
59
+ record.public_send("#{name}=", attachable)
31
60
  if record.persisted? && !record.changed?
32
- record.public_send("#{name}=", attachable)
33
- record.save
34
- else
35
- record.public_send("#{name}=", attachable)
61
+ return if !record.save
36
62
  end
63
+ record.public_send("#{name}")
37
64
  end
38
65
 
39
66
  # Returns +true+ if an attachment has been made.
@@ -47,34 +74,13 @@ module ActiveStorage
47
74
  attachment.present?
48
75
  end
49
76
 
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
77
+ private
78
+ def purge_one
79
+ Attached::Changes::PurgeOne.new(name, record, attachment)
72
80
  end
73
- end
74
81
 
75
- private
76
- def write_attachment(attachment)
77
- record.public_send("#{name}_attachment=", attachment)
82
+ def detach_one
83
+ Attached::Changes::DetachOne.new(name, record, attachment)
78
84
  end
79
85
  end
80
86
  end
@@ -3,6 +3,8 @@
3
3
  require "active_support/core_ext/module/delegation"
4
4
 
5
5
  module ActiveStorage
6
+ # = Active Storage \Attached
7
+ #
6
8
  # Abstract base class for the concrete ActiveStorage::Attached::One and ActiveStorage::Attached::Many
7
9
  # classes that both provide proxy access to the blob association for a record.
8
10
  class Attached
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveStorage
4
+ def self.deprecator # :nodoc:
5
+ @deprecator ||= ActiveSupport::Deprecation.new
6
+ end
7
+ 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