shrine 3.0.0.alpha → 3.0.0.beta
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of shrine might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +34 -2
- data/README.md +1 -1
- data/doc/creating_persistence_plugins.md +20 -63
- data/doc/plugins/activerecord.md +13 -106
- data/doc/plugins/add_metadata.md +31 -9
- data/doc/plugins/atomic_helpers.md +33 -9
- data/doc/plugins/cached_attachment_data.md +3 -3
- data/doc/plugins/data_uri.md +16 -19
- data/doc/plugins/default_storage.md +32 -8
- data/doc/plugins/default_url.md +21 -9
- data/doc/plugins/derivation_endpoint.md +48 -0
- data/doc/plugins/derivatives.md +74 -63
- data/doc/plugins/entity.md +27 -2
- data/doc/plugins/included.md +8 -7
- data/doc/plugins/metadata_attributes.md +20 -5
- data/doc/plugins/model.md +22 -2
- data/doc/plugins/persistence.md +89 -0
- data/doc/plugins/remote_url.md +41 -45
- data/doc/plugins/remove_attachment.md +23 -4
- data/doc/plugins/remove_invalid.md +3 -4
- data/doc/plugins/restore_cached_data.md +3 -1
- data/doc/plugins/sequel.md +13 -105
- data/doc/plugins/signature.md +3 -3
- data/lib/shrine/attachment.rb +11 -1
- data/lib/shrine/plugins/_persistence.rb +69 -0
- data/lib/shrine/plugins/activerecord.rb +31 -81
- data/lib/shrine/plugins/atomic_helpers.rb +13 -3
- data/lib/shrine/plugins/backgrounding.rb +8 -8
- data/lib/shrine/plugins/cached_attachment_data.rb +2 -6
- data/lib/shrine/plugins/data_uri.rb +2 -6
- data/lib/shrine/plugins/default_storage.rb +28 -2
- data/lib/shrine/plugins/derivation_endpoint.rb +3 -9
- data/lib/shrine/plugins/derivatives.rb +26 -17
- data/lib/shrine/plugins/entity.rb +24 -16
- data/lib/shrine/plugins/included.rb +1 -0
- data/lib/shrine/plugins/infer_extension.rb +2 -0
- data/lib/shrine/plugins/metadata_attributes.rb +18 -8
- data/lib/shrine/plugins/model.rb +35 -14
- data/lib/shrine/plugins/remote_url.rb +2 -6
- data/lib/shrine/plugins/remove_attachment.rb +2 -6
- data/lib/shrine/plugins/remove_invalid.rb +10 -6
- data/lib/shrine/plugins/sequel.rb +31 -78
- data/lib/shrine/plugins/upload_options.rb +2 -2
- data/lib/shrine/plugins/validation.rb +1 -11
- data/lib/shrine/version.rb +1 -1
- metadata +4 -2
@@ -11,7 +11,7 @@ class Shrine
|
|
11
11
|
# ## Promotion
|
12
12
|
#
|
13
13
|
# attacher.promote_block do
|
14
|
-
# Attachment::PromoteJob.perform_async(record, name,
|
14
|
+
# Attachment::PromoteJob.perform_async(record, name, file_data)
|
15
15
|
# end
|
16
16
|
#
|
17
17
|
# attacher.assign(io)
|
@@ -24,8 +24,8 @@ class Shrine
|
|
24
24
|
# The promote worker can be implemented like this:
|
25
25
|
#
|
26
26
|
# class Attachment::PromoteJob
|
27
|
-
# def perform(record, name,
|
28
|
-
# attacher = Shrine::Attacher.retrieve(model: record, name: name,
|
27
|
+
# def perform(record, name, file_data)
|
28
|
+
# attacher = Shrine::Attacher.retrieve(model: record, name: name, file: file_data)
|
29
29
|
# attacher.atomic_promote
|
30
30
|
# end
|
31
31
|
# end
|
@@ -65,7 +65,7 @@ class Shrine
|
|
65
65
|
# You can also register promotion and deletion hooks globally:
|
66
66
|
#
|
67
67
|
# Shrine::Attacher.promote_block do
|
68
|
-
# Attachment::PromoteJob.perform_async(record, name,
|
68
|
+
# Attachment::PromoteJob.perform_async(record, name, file_data)
|
69
69
|
# end
|
70
70
|
#
|
71
71
|
# Shrine::Attacher.destroy_block do
|
@@ -83,7 +83,7 @@ class Shrine
|
|
83
83
|
# Attachment::PromoteJob.perform_async(
|
84
84
|
# attacher.record,
|
85
85
|
# attacher.name,
|
86
|
-
# attacher.
|
86
|
+
# attacher.file_data,
|
87
87
|
# )
|
88
88
|
# end
|
89
89
|
def promote_block(&block)
|
@@ -94,7 +94,7 @@ class Shrine
|
|
94
94
|
# Registers a global deletion block.
|
95
95
|
#
|
96
96
|
# Shrine::Attacher.destroy_block do |attacher|
|
97
|
-
# Attachment::
|
97
|
+
# Attachment::DestroyJob.perform_async(attacher.data)
|
98
98
|
# end
|
99
99
|
def destroy_block(&block)
|
100
100
|
shrine_class.opts[:backgrounding][:destroy_block] = block if block
|
@@ -116,7 +116,7 @@ class Shrine
|
|
116
116
|
# Attachment::PromoteJob.perform_async(
|
117
117
|
# attacher.record,
|
118
118
|
# attacher.name
|
119
|
-
# attacher.
|
119
|
+
# attacher.file_data,
|
120
120
|
# )
|
121
121
|
# end
|
122
122
|
def promote_block(&block)
|
@@ -127,7 +127,7 @@ class Shrine
|
|
127
127
|
# Registers an instance-level deletion hook.
|
128
128
|
#
|
129
129
|
# attacher.destroy_block do |attacher|
|
130
|
-
# Attachment::
|
130
|
+
# Attachment::DestroyJob.perform_async(attacher.data)
|
131
131
|
# end
|
132
132
|
def destroy_block(&block)
|
133
133
|
@destroy_block = block if block
|
@@ -7,12 +7,8 @@ class Shrine
|
|
7
7
|
# [doc/plugins/cached_attachment_data.md]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/cached_attachment_data.md
|
8
8
|
module CachedAttachmentData
|
9
9
|
module AttachmentMethods
|
10
|
-
def
|
11
|
-
super
|
12
|
-
|
13
|
-
return unless options[:type] == :model
|
14
|
-
|
15
|
-
name = attachment_name
|
10
|
+
def define_model_methods(name)
|
11
|
+
super if defined?(super)
|
16
12
|
|
17
13
|
define_method :"cached_#{name}_data" do
|
18
14
|
send(:"#{name}_attacher").cached_data
|
@@ -39,12 +39,8 @@ class Shrine
|
|
39
39
|
end
|
40
40
|
|
41
41
|
module AttachmentMethods
|
42
|
-
def
|
43
|
-
super
|
44
|
-
|
45
|
-
return unless options[:type] == :model
|
46
|
-
|
47
|
-
name = attachment_name
|
42
|
+
def define_model_methods(name)
|
43
|
+
super if defined?(super)
|
48
44
|
|
49
45
|
define_method :"#{name}_data_uri=" do |uri|
|
50
46
|
send(:"#{name}_attacher").assign_data_uri(uri)
|
@@ -11,6 +11,22 @@ class Shrine
|
|
11
11
|
uploader.opts[:default_storage].merge!(opts)
|
12
12
|
end
|
13
13
|
|
14
|
+
module AttacherClassMethods
|
15
|
+
def default_cache(value = nil, &block)
|
16
|
+
default_storage.merge!(cache: value || block)
|
17
|
+
end
|
18
|
+
|
19
|
+
def default_store(value = nil, &block)
|
20
|
+
default_storage.merge!(store: value || block)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def default_storage
|
26
|
+
shrine_class.opts[:default_storage]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
14
30
|
module AttacherMethods
|
15
31
|
def initialize(**options)
|
16
32
|
super(**shrine_class.opts[:default_storage], **options)
|
@@ -18,7 +34,12 @@ class Shrine
|
|
18
34
|
|
19
35
|
def cache_key
|
20
36
|
if @cache.respond_to?(:call)
|
21
|
-
@cache.
|
37
|
+
if @cache.arity == 2
|
38
|
+
Shrine.deprecation("Passing record & name argument to default storage block is deprecated and will be removed in Shrine 4. Use a block without arguments instead.")
|
39
|
+
@cache.call(record, name)
|
40
|
+
else
|
41
|
+
instance_exec(&@cache)
|
42
|
+
end
|
22
43
|
else
|
23
44
|
@cache
|
24
45
|
end
|
@@ -26,7 +47,12 @@ class Shrine
|
|
26
47
|
|
27
48
|
def store_key
|
28
49
|
if @store.respond_to?(:call)
|
29
|
-
@store.
|
50
|
+
if @store.arity == 2
|
51
|
+
Shrine.deprecation("Passing record & name argument to default storage block is deprecated and will be removed in Shrine 4. Use a block without arguments instead.")
|
52
|
+
@store.call(record, name)
|
53
|
+
else
|
54
|
+
instance_exec(&@store)
|
55
|
+
end
|
30
56
|
else
|
31
57
|
@store
|
32
58
|
end
|
@@ -15,8 +15,8 @@ class Shrine
|
|
15
15
|
module DerivationEndpoint
|
16
16
|
LOG_SUBSCRIBER = -> (event) do
|
17
17
|
Shrine.logger.info "Derivation (#{event.duration}ms) – #{{
|
18
|
-
name: event[:name
|
19
|
-
args: event[:args
|
18
|
+
name: event[:derivation].name,
|
19
|
+
args: event[:derivation].args,
|
20
20
|
uploader: event[:uploader],
|
21
21
|
}.inspect}"
|
22
22
|
end
|
@@ -600,13 +600,7 @@ class Shrine
|
|
600
600
|
def instrument_derivation(&block)
|
601
601
|
return yield unless shrine_class.respond_to?(:instrument)
|
602
602
|
|
603
|
-
shrine_class.instrument(
|
604
|
-
:derivation,
|
605
|
-
name: derivation.name,
|
606
|
-
args: derivation.args,
|
607
|
-
derivation: derivation,
|
608
|
-
&block
|
609
|
-
)
|
603
|
+
shrine_class.instrument(:derivation, derivation: derivation, &block)
|
610
604
|
end
|
611
605
|
|
612
606
|
# Massages the derivation result, ensuring it's opened in binary mode,
|
@@ -29,13 +29,21 @@ class Shrine
|
|
29
29
|
end
|
30
30
|
|
31
31
|
module AttachmentMethods
|
32
|
-
def
|
33
|
-
super
|
32
|
+
def define_entity_methods(name)
|
33
|
+
super if defined?(super)
|
34
34
|
|
35
35
|
define_method(:"#{name}_derivatives") do |*args|
|
36
36
|
send(:"#{name}_attacher").get_derivatives(*args)
|
37
37
|
end
|
38
38
|
end
|
39
|
+
|
40
|
+
def define_model_methods(name)
|
41
|
+
super if defined?(super)
|
42
|
+
|
43
|
+
define_method(:"#{name}_derivatives!") do |*args|
|
44
|
+
send(:"#{name}_attacher").create_derivatives(*args)
|
45
|
+
end
|
46
|
+
end
|
39
47
|
end
|
40
48
|
|
41
49
|
module AttacherClassMethods
|
@@ -45,7 +53,12 @@ class Shrine
|
|
45
53
|
# # ...
|
46
54
|
# end
|
47
55
|
def derivatives_processor(name, &block)
|
48
|
-
|
56
|
+
if block
|
57
|
+
shrine_class.opts[:derivatives][:processors][name.to_sym] = block
|
58
|
+
else
|
59
|
+
shrine_class.opts[:derivatives][:processors][name.to_sym] or
|
60
|
+
fail Error, "derivatives processor #{name.inspect} not registered"
|
61
|
+
end
|
49
62
|
end
|
50
63
|
|
51
64
|
# Specifies default storage to which derivatives will be uploaded.
|
@@ -60,9 +73,11 @@ class Shrine
|
|
60
73
|
# end
|
61
74
|
# end
|
62
75
|
def derivatives_storage(storage_key = nil, &block)
|
63
|
-
|
64
|
-
|
65
|
-
|
76
|
+
if storage_key || block
|
77
|
+
shrine_class.opts[:derivatives][:storage] = storage_key || block
|
78
|
+
else
|
79
|
+
shrine_class.opts[:derivatives][:storage]
|
80
|
+
end
|
66
81
|
end
|
67
82
|
end
|
68
83
|
|
@@ -160,9 +175,9 @@ class Shrine
|
|
160
175
|
# end
|
161
176
|
#
|
162
177
|
# attacher.create_derivatives(:my_processor)
|
163
|
-
def create_derivatives(
|
164
|
-
files = process_derivatives(
|
165
|
-
add_derivatives(files
|
178
|
+
def create_derivatives(*args)
|
179
|
+
files = process_derivatives(*args)
|
180
|
+
add_derivatives(files)
|
166
181
|
end
|
167
182
|
|
168
183
|
# Uploads given hash of files and adds uploaded files to the
|
@@ -238,7 +253,7 @@ class Shrine
|
|
238
253
|
# attacher.process_derivatives(:thumbnails)
|
239
254
|
# #=> { small: #<File:...>, medium: #<File:...>, large: #<File:...> }
|
240
255
|
def process_derivatives(processor_name, source = nil, **options)
|
241
|
-
processor = derivatives_processor(processor_name)
|
256
|
+
processor = self.class.derivatives_processor(processor_name)
|
242
257
|
fetch_source = source ? source.method(:tap) : file!.method(:download)
|
243
258
|
result = nil
|
244
259
|
|
@@ -458,12 +473,6 @@ class Shrine
|
|
458
473
|
)
|
459
474
|
end
|
460
475
|
|
461
|
-
# Retrieves derivatives processor with specified name.
|
462
|
-
def derivatives_processor(name)
|
463
|
-
shrine_class.opts[:derivatives][:processors][name.to_sym] or
|
464
|
-
fail Error, "derivatives processor #{name.inspect} not registered"
|
465
|
-
end
|
466
|
-
|
467
476
|
# Returns symbolized array or single key.
|
468
477
|
def derivative_path(path)
|
469
478
|
path = path.map { |key| key.is_a?(String) ? key.to_sym : key }
|
@@ -473,7 +482,7 @@ class Shrine
|
|
473
482
|
|
474
483
|
# Storage to which derivatives will be uploaded to by default.
|
475
484
|
def derivative_storage(path)
|
476
|
-
storage =
|
485
|
+
storage = self.class.derivatives_storage
|
477
486
|
storage = instance_exec(path, &storage) if storage.respond_to?(:call)
|
478
487
|
storage
|
479
488
|
end
|
@@ -11,9 +11,18 @@ class Shrine
|
|
11
11
|
end
|
12
12
|
|
13
13
|
module AttachmentMethods
|
14
|
+
attr_reader :type
|
15
|
+
|
16
|
+
def initialize(name, type: :entity, **options)
|
17
|
+
super(name, **options)
|
18
|
+
@type = type
|
19
|
+
|
20
|
+
define_entity_methods(name)
|
21
|
+
end
|
22
|
+
|
14
23
|
# Defines `#<name>`, `#<name>_url`, and `#<name>_attacher` methods.
|
15
|
-
def
|
16
|
-
super
|
24
|
+
def define_entity_methods(name)
|
25
|
+
super if defined?(super)
|
17
26
|
|
18
27
|
attachment = self
|
19
28
|
|
@@ -36,7 +45,9 @@ class Shrine
|
|
36
45
|
# Creates an instance of the corresponding Attacher subclass. It's not
|
37
46
|
# memoized because the entity object could be frozen.
|
38
47
|
def attacher(record, options)
|
39
|
-
|
48
|
+
attacher = record.class.send(:"#{@name}_attacher", options)
|
49
|
+
attacher.load_entity(record, @name)
|
50
|
+
attacher
|
40
51
|
end
|
41
52
|
end
|
42
53
|
|
@@ -47,9 +58,9 @@ class Shrine
|
|
47
58
|
#
|
48
59
|
# attacher = Attacher.from_entity(photo, :image)
|
49
60
|
# attacher.file #=> #<Shrine::UploadedFile>
|
50
|
-
def from_entity(record, name,
|
61
|
+
def from_entity(record, name, **options)
|
51
62
|
attacher = new(**options)
|
52
|
-
attacher.load_entity(record, name
|
63
|
+
attacher.load_entity(record, name)
|
53
64
|
attacher
|
54
65
|
end
|
55
66
|
end
|
@@ -59,14 +70,18 @@ class Shrine
|
|
59
70
|
|
60
71
|
# Saves record and name and initializes attachment from the entity
|
61
72
|
# attribute. Called from `Attacher.from_entity`.
|
62
|
-
def load_entity(record, name
|
73
|
+
def load_entity(record, name)
|
74
|
+
set_entity(record, name)
|
75
|
+
read
|
76
|
+
end
|
77
|
+
|
78
|
+
# Sets record and name without loading the attachment from the entity
|
79
|
+
# attribute.
|
80
|
+
def set_entity(record, name)
|
63
81
|
@record = record
|
64
82
|
@name = name.to_sym
|
65
|
-
@type = type
|
66
83
|
|
67
84
|
@context.merge!(record: record, name: name)
|
68
|
-
|
69
|
-
read
|
70
85
|
end
|
71
86
|
|
72
87
|
# Overwrites the current attachment with the one from model attribute.
|
@@ -113,13 +128,6 @@ class Shrine
|
|
113
128
|
def read_attribute
|
114
129
|
record.public_send(attribute)
|
115
130
|
end
|
116
|
-
|
117
|
-
# Returns whether the attacher has been loaded from an entity instance.
|
118
|
-
def entity?
|
119
|
-
type == :entity
|
120
|
-
end
|
121
|
-
|
122
|
-
attr_reader :type
|
123
131
|
end
|
124
132
|
end
|
125
133
|
|
@@ -10,27 +10,37 @@ class Shrine
|
|
10
10
|
uploader.plugin :entity
|
11
11
|
end
|
12
12
|
|
13
|
-
def self.configure(uploader,
|
14
|
-
uploader.opts[:metadata_attributes] ||= {
|
15
|
-
uploader.opts[:metadata_attributes]
|
13
|
+
def self.configure(uploader, **opts)
|
14
|
+
uploader.opts[:metadata_attributes] ||= {}
|
15
|
+
uploader.opts[:metadata_attributes].merge!(opts)
|
16
16
|
end
|
17
17
|
|
18
18
|
module AttacherClassMethods
|
19
|
-
def metadata_attributes(mappings)
|
20
|
-
|
19
|
+
def metadata_attributes(mappings = nil)
|
20
|
+
if mappings
|
21
|
+
shrine_class.opts[:metadata_attributes].merge!(mappings)
|
22
|
+
else
|
23
|
+
shrine_class.opts[:metadata_attributes]
|
24
|
+
end
|
21
25
|
end
|
22
26
|
end
|
23
27
|
|
24
28
|
module AttacherMethods
|
25
29
|
def column_values
|
26
|
-
|
30
|
+
super.merge(metadata_attributes)
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def metadata_attributes
|
36
|
+
values = {}
|
27
37
|
|
28
|
-
|
38
|
+
self.class.metadata_attributes.each do |source, destination|
|
29
39
|
metadata_attribute = destination.is_a?(Symbol) ? :"#{name}_#{destination}" : :"#{destination}"
|
30
40
|
|
31
41
|
next unless record.respond_to?(metadata_attribute)
|
32
42
|
|
33
|
-
values[metadata_attribute] = file
|
43
|
+
values[metadata_attribute] = file&.metadata[source.to_s]
|
34
44
|
end
|
35
45
|
|
36
46
|
values
|
data/lib/shrine/plugins/model.rb
CHANGED
@@ -26,19 +26,31 @@ class Shrine
|
|
26
26
|
super(name, type: :model, **options)
|
27
27
|
end
|
28
28
|
|
29
|
-
# We define
|
30
|
-
#
|
29
|
+
# We define model methods only on inclusion, if the attachment type is
|
30
|
+
# still "model". This gives other plugins the ability to force
|
31
|
+
# attachment type to "entity" for certain classes, and we can skip
|
32
|
+
# defining model methods in this case.
|
31
33
|
def included(klass)
|
32
34
|
super
|
33
35
|
|
34
|
-
return unless
|
36
|
+
return unless type == :model
|
35
37
|
|
36
|
-
name
|
38
|
+
define_model_methods(@name)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Defines attachment setter and enhances the copy constructor.
|
42
|
+
def define_model_methods(name)
|
43
|
+
super if defined?(super)
|
37
44
|
|
38
45
|
define_method :"#{name}=" do |value|
|
39
46
|
send(:"#{name}_attacher").model_assign(value)
|
40
47
|
end
|
41
48
|
|
49
|
+
define_method :"#{name}_changed?" do
|
50
|
+
send(:"#{name}_attacher").changed?
|
51
|
+
end
|
52
|
+
|
53
|
+
# The copy constructor that's called on #dup and #clone.
|
42
54
|
define_method :initialize_copy do |other|
|
43
55
|
super(other)
|
44
56
|
instance_variable_set(:"@#{name}_attacher", instance_variable_get(:"@#{name}_attacher")&.dup)
|
@@ -49,14 +61,15 @@ class Shrine
|
|
49
61
|
|
50
62
|
# Memoizes the attacher instance into an instance variable.
|
51
63
|
def attacher(record, options)
|
52
|
-
return super unless
|
64
|
+
return super unless type == :model
|
53
65
|
|
54
|
-
name
|
66
|
+
if !record.instance_variable_get(:"@#{@name}_attacher") || options.any?
|
67
|
+
attacher = super
|
68
|
+
attacher.set_model(record, @name)
|
55
69
|
|
56
|
-
|
57
|
-
record.instance_variable_set(:"@#{name}_attacher", super)
|
70
|
+
record.instance_variable_set(:"@#{@name}_attacher", attacher)
|
58
71
|
else
|
59
|
-
record.instance_variable_get(:"@#{name}_attacher")
|
72
|
+
record.instance_variable_get(:"@#{@name}_attacher")
|
60
73
|
end
|
61
74
|
end
|
62
75
|
end
|
@@ -68,9 +81,9 @@ class Shrine
|
|
68
81
|
#
|
69
82
|
# attacher = Attacher.from_model(photo, :image)
|
70
83
|
# attacher.file #=> #<Shrine::UploadedFile>
|
71
|
-
def from_model(record, name,
|
84
|
+
def from_model(record, name, **options)
|
72
85
|
attacher = new(**options)
|
73
|
-
attacher.load_model(record, name
|
86
|
+
attacher.load_model(record, name)
|
74
87
|
attacher
|
75
88
|
end
|
76
89
|
end
|
@@ -83,8 +96,16 @@ class Shrine
|
|
83
96
|
|
84
97
|
# Saves record and name and initializes attachment from the model
|
85
98
|
# attribute. Called from `Attacher.from_model`.
|
86
|
-
def load_model(record, name
|
87
|
-
|
99
|
+
def load_model(record, name)
|
100
|
+
set_model(record, name)
|
101
|
+
read
|
102
|
+
end
|
103
|
+
|
104
|
+
# Saves record and name without loading attachment from the model
|
105
|
+
# attribute.
|
106
|
+
def set_model(record, name)
|
107
|
+
set_entity(record, name)
|
108
|
+
@model = true
|
88
109
|
end
|
89
110
|
|
90
111
|
# Called by the attachment attribute setter on the model.
|
@@ -127,7 +148,7 @@ class Shrine
|
|
127
148
|
# This allows users to still use the attacher with an entity instance
|
128
149
|
# or without any record instance.
|
129
150
|
def model?
|
130
|
-
|
151
|
+
instance_variable_defined?(:@model)
|
131
152
|
end
|
132
153
|
end
|
133
154
|
end
|
@@ -43,12 +43,8 @@ class Shrine
|
|
43
43
|
end
|
44
44
|
|
45
45
|
module AttachmentMethods
|
46
|
-
def
|
47
|
-
super
|
48
|
-
|
49
|
-
return unless options[:type] == :model
|
50
|
-
|
51
|
-
name = attachment_name
|
46
|
+
def define_model_methods(name)
|
47
|
+
super if defined?(super)
|
52
48
|
|
53
49
|
define_method :"#{name}_remote_url=" do |url|
|
54
50
|
send(:"#{name}_attacher").assign_remote_url(url)
|
@@ -7,12 +7,8 @@ class Shrine
|
|
7
7
|
# [doc/plugins/remove_attachment.md]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/remove_attachment.md
|
8
8
|
module RemoveAttachment
|
9
9
|
module AttachmentMethods
|
10
|
-
def
|
11
|
-
super
|
12
|
-
|
13
|
-
return unless options[:type] == :model
|
14
|
-
|
15
|
-
name = attachment_name
|
10
|
+
def define_model_methods(name)
|
11
|
+
super if defined?(super)
|
16
12
|
|
17
13
|
define_method :"remove_#{name}=" do |value|
|
18
14
|
send(:"#{name}_attacher").remove = value
|
@@ -11,14 +11,18 @@ class Shrine
|
|
11
11
|
end
|
12
12
|
|
13
13
|
module AttacherMethods
|
14
|
-
def
|
14
|
+
def change(*)
|
15
15
|
super
|
16
16
|
ensure
|
17
|
-
if errors.any?
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
17
|
+
revert_change if errors.any?
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def revert_change
|
23
|
+
destroy(background: true)
|
24
|
+
set @previous.file
|
25
|
+
remove_instance_variable(:@previous)
|
22
26
|
end
|
23
27
|
end
|
24
28
|
end
|