activestorage 6.1.3.1 → 7.0.0.alpha1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +131 -181
- data/MIT-LICENSE +1 -1
- data/README.md +25 -11
- data/app/assets/javascripts/activestorage.esm.js +844 -0
- data/app/assets/javascripts/activestorage.js +257 -376
- data/app/controllers/active_storage/base_controller.rb +1 -10
- data/app/controllers/active_storage/blobs/proxy_controller.rb +14 -4
- data/app/controllers/active_storage/blobs/redirect_controller.rb +6 -4
- data/app/controllers/active_storage/representations/base_controller.rb +18 -0
- data/app/controllers/active_storage/representations/proxy_controller.rb +7 -11
- data/app/controllers/active_storage/representations/redirect_controller.rb +7 -7
- data/app/controllers/concerns/active_storage/set_blob.rb +6 -2
- data/app/controllers/concerns/active_storage/set_current.rb +3 -3
- data/app/controllers/concerns/active_storage/streaming.rb +65 -0
- data/app/javascript/activestorage/ujs.js +1 -1
- data/app/models/active_storage/attachment.rb +36 -3
- data/app/models/active_storage/blob/representable.rb +8 -6
- data/app/models/active_storage/blob.rb +27 -28
- data/app/models/active_storage/current.rb +12 -2
- data/app/models/active_storage/preview.rb +6 -4
- data/app/models/active_storage/record.rb +1 -1
- data/app/models/active_storage/variant.rb +4 -7
- data/app/models/active_storage/variant_record.rb +2 -0
- data/app/models/active_storage/variant_with_record.rb +10 -6
- data/app/models/active_storage/variation.rb +2 -2
- data/config/routes.rb +10 -10
- data/db/migrate/20170806125915_create_active_storage_tables.rb +29 -8
- data/db/update_migrate/20191206030411_create_active_storage_variant_records.rb +15 -2
- data/lib/active_storage/analyzer/audio_analyzer.rb +65 -0
- data/lib/active_storage/analyzer/image_analyzer/image_magick.rb +39 -0
- data/lib/active_storage/analyzer/image_analyzer/vips.rb +49 -0
- data/lib/active_storage/analyzer/image_analyzer.rb +2 -30
- data/lib/active_storage/analyzer/video_analyzer.rb +26 -11
- data/lib/active_storage/analyzer.rb +8 -4
- data/lib/active_storage/attached/changes/create_many.rb +7 -3
- data/lib/active_storage/attached/changes/create_one.rb +1 -1
- data/lib/active_storage/attached/changes/create_one_of_many.rb +1 -1
- data/lib/active_storage/attached/changes/delete_many.rb +1 -1
- data/lib/active_storage/attached/changes/delete_one.rb +1 -1
- data/lib/active_storage/attached/changes/detach_many.rb +18 -0
- data/lib/active_storage/attached/changes/detach_one.rb +24 -0
- data/lib/active_storage/attached/changes/purge_many.rb +27 -0
- data/lib/active_storage/attached/changes/purge_one.rb +27 -0
- data/lib/active_storage/attached/changes.rb +7 -1
- data/lib/active_storage/attached/many.rb +27 -15
- data/lib/active_storage/attached/model.rb +31 -5
- data/lib/active_storage/attached/one.rb +32 -27
- data/lib/active_storage/downloader.rb +2 -2
- data/lib/active_storage/engine.rb +29 -1
- data/lib/active_storage/errors.rb +3 -0
- data/lib/active_storage/fixture_set.rb +76 -0
- data/lib/active_storage/gem_version.rb +4 -4
- data/lib/active_storage/previewer/video_previewer.rb +1 -1
- data/lib/active_storage/previewer.rb +14 -5
- data/lib/active_storage/reflection.rb +12 -2
- data/lib/active_storage/service/azure_storage_service.rb +1 -1
- data/lib/active_storage/service/configurator.rb +1 -1
- data/lib/active_storage/service/disk_service.rb +13 -18
- data/lib/active_storage/service/gcs_service.rb +91 -7
- data/lib/active_storage/service/mirror_service.rb +1 -1
- data/lib/active_storage/service/registry.rb +1 -1
- data/lib/active_storage/service/s3_service.rb +4 -4
- data/lib/active_storage/service.rb +3 -3
- data/lib/active_storage/transformers/image_processing_transformer.rb +1 -1
- data/lib/active_storage/transformers/transformer.rb +1 -1
- data/lib/active_storage.rb +5 -1
- data/lib/tasks/activestorage.rake +5 -1
- metadata +32 -22
- data/app/controllers/concerns/active_storage/set_headers.rb +0 -12
@@ -1,17 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveStorage
|
4
|
-
#
|
4
|
+
# This is an abstract base class for image analyzers, which extract width and height from an image blob.
|
5
5
|
#
|
6
6
|
# If the image contains EXIF data indicating its angle is 90 or 270 degrees, its width and height are swapped for convenience.
|
7
7
|
#
|
8
8
|
# Example:
|
9
9
|
#
|
10
|
-
# ActiveStorage::Analyzer::ImageAnalyzer.new(blob).metadata
|
10
|
+
# ActiveStorage::Analyzer::ImageAnalyzer::ImageMagick.new(blob).metadata
|
11
11
|
# # => { width: 4104, height: 2736 }
|
12
|
-
#
|
13
|
-
# This analyzer relies on the third-party {MiniMagick}[https://github.com/minimagick/minimagick] gem. MiniMagick requires
|
14
|
-
# the {ImageMagick}[http://www.imagemagick.org] system library.
|
15
12
|
class Analyzer::ImageAnalyzer < Analyzer
|
16
13
|
def self.accept?(blob)
|
17
14
|
blob.image?
|
@@ -26,30 +23,5 @@ module ActiveStorage
|
|
26
23
|
end
|
27
24
|
end
|
28
25
|
end
|
29
|
-
|
30
|
-
private
|
31
|
-
def read_image
|
32
|
-
download_blob_to_tempfile do |file|
|
33
|
-
require "mini_magick"
|
34
|
-
image = MiniMagick::Image.new(file.path)
|
35
|
-
|
36
|
-
if image.valid?
|
37
|
-
yield image
|
38
|
-
else
|
39
|
-
logger.info "Skipping image analysis because ImageMagick doesn't support the file"
|
40
|
-
{}
|
41
|
-
end
|
42
|
-
end
|
43
|
-
rescue LoadError
|
44
|
-
logger.info "Skipping image analysis because the mini_magick gem isn't installed"
|
45
|
-
{}
|
46
|
-
rescue MiniMagick::Error => error
|
47
|
-
logger.error "Skipping image analysis due to an ImageMagick error: #{error.message}"
|
48
|
-
{}
|
49
|
-
end
|
50
|
-
|
51
|
-
def rotated_image?(image)
|
52
|
-
%w[ RightTop LeftBottom ].include?(image["%[orientation]"])
|
53
|
-
end
|
54
26
|
end
|
55
27
|
end
|
@@ -8,11 +8,13 @@ module ActiveStorage
|
|
8
8
|
# * Duration (seconds)
|
9
9
|
# * Angle (degrees)
|
10
10
|
# * Display aspect ratio
|
11
|
+
# * Audio (true if file has an audio channel, false if not)
|
12
|
+
# * Video (true if file has an video channel, false if not)
|
11
13
|
#
|
12
14
|
# Example:
|
13
15
|
#
|
14
16
|
# ActiveStorage::Analyzer::VideoAnalyzer.new(blob).metadata
|
15
|
-
# # => { width: 640.0, height: 480.0, duration: 5.0, angle: 0, display_aspect_ratio: [4, 3] }
|
17
|
+
# # => { width: 640.0, height: 480.0, duration: 5.0, angle: 0, display_aspect_ratio: [4, 3], audio: true, video: true }
|
16
18
|
#
|
17
19
|
# When a video's angle is 90 or 270 degrees, its width and height are automatically swapped for convenience.
|
18
20
|
#
|
@@ -23,7 +25,7 @@ module ActiveStorage
|
|
23
25
|
end
|
24
26
|
|
25
27
|
def metadata
|
26
|
-
{ width: width, height: height, duration: duration, angle: angle, display_aspect_ratio: display_aspect_ratio }.compact
|
28
|
+
{ width: width, height: height, duration: duration, angle: angle, display_aspect_ratio: display_aspect_ratio, audio: audio?, video: video? }.compact
|
27
29
|
end
|
28
30
|
|
29
31
|
private
|
@@ -63,11 +65,18 @@ module ActiveStorage
|
|
63
65
|
end
|
64
66
|
end
|
65
67
|
|
66
|
-
|
67
68
|
def rotated?
|
68
69
|
angle == 90 || angle == 270
|
69
70
|
end
|
70
71
|
|
72
|
+
def audio?
|
73
|
+
audio_stream.present?
|
74
|
+
end
|
75
|
+
|
76
|
+
def video?
|
77
|
+
video_stream.present?
|
78
|
+
end
|
79
|
+
|
71
80
|
def computed_height
|
72
81
|
if encoded_width && display_height_scale
|
73
82
|
encoded_width * display_height_scale
|
@@ -95,6 +104,10 @@ module ActiveStorage
|
|
95
104
|
@video_stream ||= streams.detect { |stream| stream["codec_type"] == "video" } || {}
|
96
105
|
end
|
97
106
|
|
107
|
+
def audio_stream
|
108
|
+
@audio_stream ||= streams.detect { |stream| stream["codec_type"] == "audio" } || {}
|
109
|
+
end
|
110
|
+
|
98
111
|
def streams
|
99
112
|
probe["streams"] || []
|
100
113
|
end
|
@@ -108,14 +121,16 @@ module ActiveStorage
|
|
108
121
|
end
|
109
122
|
|
110
123
|
def probe_from(file)
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
124
|
+
instrument(File.basename(ffprobe_path)) do
|
125
|
+
IO.popen([ ffprobe_path,
|
126
|
+
"-print_format", "json",
|
127
|
+
"-show_streams",
|
128
|
+
"-show_format",
|
129
|
+
"-v", "error",
|
130
|
+
file.path
|
131
|
+
]) do |output|
|
132
|
+
JSON.parse(output.read)
|
133
|
+
end
|
119
134
|
end
|
120
135
|
rescue Errno::ENOENT
|
121
136
|
logger.info "Skipping video analysis because FFmpeg isn't installed"
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module ActiveStorage
|
4
4
|
# This is an abstract base class for analyzers, which extract metadata from blobs. See
|
5
|
-
# ActiveStorage::Analyzer::
|
5
|
+
# ActiveStorage::Analyzer::VideoAnalyzer for an example of a concrete subclass.
|
6
6
|
class Analyzer
|
7
7
|
attr_reader :blob
|
8
8
|
|
@@ -29,16 +29,20 @@ module ActiveStorage
|
|
29
29
|
|
30
30
|
private
|
31
31
|
# Downloads the blob to a tempfile on disk. Yields the tempfile.
|
32
|
-
def download_blob_to_tempfile(&block)
|
32
|
+
def download_blob_to_tempfile(&block) # :doc:
|
33
33
|
blob.open tmpdir: tmpdir, &block
|
34
34
|
end
|
35
35
|
|
36
|
-
def logger
|
36
|
+
def logger # :doc:
|
37
37
|
ActiveStorage.logger
|
38
38
|
end
|
39
39
|
|
40
|
-
def tmpdir
|
40
|
+
def tmpdir # :doc:
|
41
41
|
Dir.tmpdir
|
42
42
|
end
|
43
|
+
|
44
|
+
def instrument(analyzer, &block) # :doc:
|
45
|
+
ActiveSupport::Notifications.instrument("analyze.active_storage", analyzer: analyzer, &block)
|
46
|
+
end
|
43
47
|
end
|
44
48
|
end
|
@@ -1,12 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveStorage
|
4
|
-
class Attached::Changes::CreateMany
|
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=",
|
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
|
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
|
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 }
|
@@ -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
|
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/
|
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
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
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
|
-
|
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
|
|
@@ -144,6 +145,12 @@ module ActiveStorage
|
|
144
145
|
ActiveStorage::Attached::Changes::CreateMany.new("#{name}", self, attachables)
|
145
146
|
end
|
146
147
|
else
|
148
|
+
ActiveSupport::Deprecation.warn \
|
149
|
+
"config.active_storage.replace_on_assign_to_many is deprecated and will be removed in Rails 7.1. " \
|
150
|
+
"Make sure that your code works well with config.active_storage.replace_on_assign_to_many set to true before upgrading. " \
|
151
|
+
"To append new attachables to the Active Storage association, prefer using `attach`. " \
|
152
|
+
"Using association setter would result in purging the existing attached attachments and replacing them with new ones."
|
153
|
+
|
147
154
|
if Array(attachables).any?
|
148
155
|
attachment_changes["#{name}"] =
|
149
156
|
ActiveStorage::Attached::Changes::CreateMany.new("#{name}", self, #{name}.blobs + attachables)
|
@@ -154,18 +161,36 @@ module ActiveStorage
|
|
154
161
|
|
155
162
|
has_many :"#{name}_attachments", -> { where(name: name) }, as: :record, class_name: "ActiveStorage::Attachment", inverse_of: :record, dependent: :destroy, strict_loading: strict_loading do
|
156
163
|
def purge
|
164
|
+
deprecate(:purge)
|
157
165
|
each(&:purge)
|
158
166
|
reset
|
159
167
|
end
|
160
168
|
|
161
169
|
def purge_later
|
170
|
+
deprecate(:purge_later)
|
162
171
|
each(&:purge_later)
|
163
172
|
reset
|
164
173
|
end
|
174
|
+
|
175
|
+
private
|
176
|
+
def deprecate(action)
|
177
|
+
reflection_name = proxy_association.reflection.name
|
178
|
+
attached_name = reflection_name.to_s.partition("_").first
|
179
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
180
|
+
Calling `#{action}` from `#{reflection_name}` is deprecated and will be removed in Rails 7.1.
|
181
|
+
To migrate to Rails 7.1's behavior call `#{action}` from `#{attached_name}` instead: `#{attached_name}.#{action}`.
|
182
|
+
MSG
|
183
|
+
end
|
165
184
|
end
|
166
185
|
has_many :"#{name}_blobs", through: :"#{name}_attachments", class_name: "ActiveStorage::Blob", source: :blob, strict_loading: strict_loading
|
167
186
|
|
168
|
-
scope :"with_attached_#{name}", -> {
|
187
|
+
scope :"with_attached_#{name}", -> {
|
188
|
+
if ActiveStorage.track_variants
|
189
|
+
includes("#{name}_attachments": { blob: :variant_records })
|
190
|
+
else
|
191
|
+
includes("#{name}_attachments": :blob)
|
192
|
+
end
|
193
|
+
}
|
169
194
|
|
170
195
|
after_save { attachment_changes[name.to_s]&.save }
|
171
196
|
|
@@ -178,6 +203,7 @@ module ActiveStorage
|
|
178
203
|
{ dependent: dependent, service_name: service },
|
179
204
|
self
|
180
205
|
)
|
206
|
+
yield reflection if block_given?
|
181
207
|
ActiveRecord::Reflection.add_attachment_reflection(self, name, reflection)
|
182
208
|
end
|
183
209
|
|
@@ -191,21 +217,21 @@ module ActiveStorage
|
|
191
217
|
end
|
192
218
|
end
|
193
219
|
|
194
|
-
def attachment_changes
|
220
|
+
def attachment_changes # :nodoc:
|
195
221
|
@attachment_changes ||= {}
|
196
222
|
end
|
197
223
|
|
198
|
-
def changed_for_autosave?
|
224
|
+
def changed_for_autosave? # :nodoc:
|
199
225
|
super || attachment_changes.any?
|
200
226
|
end
|
201
227
|
|
202
|
-
def initialize_dup(*)
|
228
|
+
def initialize_dup(*) # :nodoc:
|
203
229
|
super
|
204
230
|
@active_storage_attached = nil
|
205
231
|
@attachment_changes = nil
|
206
232
|
end
|
207
233
|
|
208
|
-
def reload(*)
|
234
|
+
def reload(*) # :nodoc:
|
209
235
|
super.tap { @attachment_changes = nil }
|
210
236
|
end
|
211
237
|
end
|