shrine 3.1.0 → 3.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +82 -0
- data/README.md +11 -4
- data/doc/advantages.md +4 -4
- data/doc/attacher.md +2 -2
- data/doc/carrierwave.md +24 -12
- data/doc/changing_derivatives.md +1 -1
- data/doc/changing_location.md +6 -5
- data/doc/design.md +134 -85
- data/doc/direct_s3.md +26 -0
- data/doc/external/articles.md +57 -45
- data/doc/external/extensions.md +41 -35
- data/doc/external/misc.md +23 -8
- data/doc/getting_started.md +156 -85
- data/doc/metadata.md +80 -44
- data/doc/multiple_files.md +1 -1
- data/doc/paperclip.md +28 -9
- data/doc/plugins/add_metadata.md +112 -35
- data/doc/plugins/atomic_helpers.md +41 -3
- data/doc/plugins/backgrounding.md +12 -2
- data/doc/plugins/column.md +36 -7
- data/doc/plugins/default_url.md +6 -3
- data/doc/plugins/derivatives.md +83 -44
- data/doc/plugins/download_endpoint.md +5 -5
- data/doc/plugins/dynamic_storage.md +1 -1
- data/doc/plugins/entity.md +12 -4
- data/doc/plugins/form_assign.md +5 -5
- data/doc/plugins/included.md +25 -5
- data/doc/plugins/infer_extension.md +9 -0
- data/doc/plugins/instrumentation.md +1 -1
- data/doc/plugins/metadata_attributes.md +1 -0
- data/doc/plugins/mirroring.md +1 -1
- data/doc/plugins/model.md +8 -3
- data/doc/plugins/persistence.md +10 -1
- data/doc/plugins/remote_url.md +6 -1
- data/doc/plugins/remove_invalid.md +9 -1
- data/doc/plugins/sequel.md +1 -1
- data/doc/plugins/store_dimensions.md +10 -0
- data/doc/plugins/type_predicates.md +96 -0
- data/doc/plugins/upload_endpoint.md +1 -1
- data/doc/plugins/upload_options.md +1 -1
- data/doc/plugins/url_options.md +4 -4
- data/doc/plugins/validation.md +14 -4
- data/doc/plugins/versions.md +7 -7
- data/doc/processing.md +287 -123
- data/doc/refile.md +9 -9
- data/doc/release_notes/2.8.0.md +1 -1
- data/doc/release_notes/3.0.0.md +1 -1
- data/doc/release_notes/3.2.0.md +96 -0
- data/doc/release_notes/3.2.1.md +31 -0
- data/doc/release_notes/3.2.2.md +14 -0
- data/doc/release_notes/3.3.0.md +105 -0
- data/doc/release_notes/3.4.0.md +35 -0
- data/doc/securing_uploads.md +2 -2
- data/doc/storage/memory.md +19 -0
- data/doc/storage/s3.md +104 -77
- data/doc/testing.md +12 -2
- data/doc/upgrading_to_3.md +99 -53
- data/lib/shrine.rb +9 -8
- data/lib/shrine/attacher.rb +20 -10
- data/lib/shrine/attachment.rb +2 -2
- data/lib/shrine/plugins.rb +22 -0
- data/lib/shrine/plugins/activerecord.rb +3 -3
- data/lib/shrine/plugins/add_metadata.rb +20 -5
- data/lib/shrine/plugins/backgrounding.rb +2 -2
- data/lib/shrine/plugins/default_url.rb +1 -1
- data/lib/shrine/plugins/derivation_endpoint.rb +13 -8
- data/lib/shrine/plugins/derivatives.rb +59 -30
- data/lib/shrine/plugins/determine_mime_type.rb +5 -3
- data/lib/shrine/plugins/entity.rb +12 -11
- data/lib/shrine/plugins/instrumentation.rb +12 -18
- data/lib/shrine/plugins/mirroring.rb +8 -8
- data/lib/shrine/plugins/model.rb +3 -3
- data/lib/shrine/plugins/presign_endpoint.rb +16 -4
- data/lib/shrine/plugins/pretty_location.rb +1 -1
- data/lib/shrine/plugins/processing.rb +1 -1
- data/lib/shrine/plugins/refresh_metadata.rb +2 -2
- data/lib/shrine/plugins/remote_url.rb +3 -3
- data/lib/shrine/plugins/remove_attachment.rb +5 -0
- data/lib/shrine/plugins/remove_invalid.rb +10 -5
- data/lib/shrine/plugins/sequel.rb +1 -1
- data/lib/shrine/plugins/store_dimensions.rb +4 -2
- data/lib/shrine/plugins/type_predicates.rb +113 -0
- data/lib/shrine/plugins/upload_endpoint.rb +10 -5
- data/lib/shrine/plugins/upload_options.rb +2 -2
- data/lib/shrine/plugins/url_options.rb +2 -2
- data/lib/shrine/plugins/validation.rb +9 -7
- data/lib/shrine/storage/linter.rb +4 -4
- data/lib/shrine/storage/memory.rb +5 -3
- data/lib/shrine/storage/s3.rb +117 -38
- data/lib/shrine/version.rb +1 -1
- data/shrine.gemspec +8 -8
- metadata +42 -34
data/lib/shrine/attachment.rb
CHANGED
data/lib/shrine/plugins.rb
CHANGED
@@ -18,6 +18,28 @@ class Shrine
|
|
18
18
|
plugin
|
19
19
|
end
|
20
20
|
|
21
|
+
# Delegate call to the plugin in a way that works across Ruby versions.
|
22
|
+
def self.load_dependencies(plugin, uploader, *args, **kwargs, &block)
|
23
|
+
return unless plugin.respond_to?(:load_dependencies)
|
24
|
+
|
25
|
+
if kwargs.any?
|
26
|
+
plugin.load_dependencies(uploader, *args, **kwargs, &block)
|
27
|
+
else
|
28
|
+
plugin.load_dependencies(uploader, *args, &block)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Delegate call to the plugin in a way that works across Ruby versions.
|
33
|
+
def self.configure(plugin, uploader, *args, **kwargs, &block)
|
34
|
+
return unless plugin.respond_to?(:configure)
|
35
|
+
|
36
|
+
if kwargs.any?
|
37
|
+
plugin.configure(uploader, *args, **kwargs, &block)
|
38
|
+
else
|
39
|
+
plugin.configure(uploader, *args, &block)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
21
43
|
# Register the given plugin with Shrine, so that it can be loaded using
|
22
44
|
# `Shrine.plugin` with a symbol. Should be used by plugin files. Example:
|
23
45
|
#
|
@@ -55,7 +55,7 @@ class Shrine
|
|
55
55
|
# reload the attacher on record reload
|
56
56
|
define_method :reload do |*args|
|
57
57
|
result = super(*args)
|
58
|
-
|
58
|
+
send(:"#{name}_attacher").reload if instance_variable_defined?(:"@#{name}_attacher")
|
59
59
|
result
|
60
60
|
end
|
61
61
|
end
|
@@ -75,8 +75,8 @@ class Shrine
|
|
75
75
|
def activerecord_validate
|
76
76
|
return unless respond_to?(:errors)
|
77
77
|
|
78
|
-
errors.each do |
|
79
|
-
record.errors.add(name,
|
78
|
+
errors.each do |(type, options)|
|
79
|
+
record.errors.add(name, type, **options.to_h)
|
80
80
|
end
|
81
81
|
end
|
82
82
|
|
@@ -9,8 +9,8 @@ class Shrine
|
|
9
9
|
end
|
10
10
|
|
11
11
|
module ClassMethods
|
12
|
-
def add_metadata(name = nil, &block)
|
13
|
-
opts[:add_metadata][:definitions] << [name, block]
|
12
|
+
def add_metadata(name = nil, **options, &block)
|
13
|
+
opts[:add_metadata][:definitions] << [name, options, block]
|
14
14
|
|
15
15
|
metadata_method(name) if name
|
16
16
|
end
|
@@ -40,10 +40,12 @@ class Shrine
|
|
40
40
|
private
|
41
41
|
|
42
42
|
def extract_custom_metadata(io, **options)
|
43
|
-
opts[:add_metadata][:definitions].each do |name, block|
|
44
|
-
result = instance_exec(io, options, &block)
|
43
|
+
opts[:add_metadata][:definitions].each do |name, definition_options, block|
|
44
|
+
result = instance_exec(io, **options, &block)
|
45
45
|
|
46
|
-
if
|
46
|
+
if result.nil? && definition_options[:skip_nil]
|
47
|
+
# Do not store this metadata
|
48
|
+
elsif name
|
47
49
|
options[:metadata].merge! name.to_s => result
|
48
50
|
else
|
49
51
|
options[:metadata].merge! result.transform_keys(&:to_s) if result
|
@@ -54,6 +56,19 @@ class Shrine
|
|
54
56
|
end
|
55
57
|
end
|
56
58
|
end
|
59
|
+
|
60
|
+
module AttacherMethods
|
61
|
+
def add_metadata(new_metadata, &block)
|
62
|
+
file!.add_metadata(new_metadata, &block)
|
63
|
+
set(file) # trigger model write
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
module FileMethods
|
68
|
+
def add_metadata(new_metadata, &block)
|
69
|
+
@metadata = @metadata.merge(new_metadata, &block)
|
70
|
+
end
|
71
|
+
end
|
57
72
|
end
|
58
73
|
|
59
74
|
register_plugin(:add_metadata, AddMetadata)
|
@@ -392,6 +392,7 @@ class Shrine
|
|
392
392
|
options[:type] = request.params["type"] if request.params["type"]
|
393
393
|
options[:disposition] = request.params["disposition"] if request.params["disposition"]
|
394
394
|
options[:filename] = request.params["filename"] if request.params["filename"]
|
395
|
+
options[:version] = request.params["version"] if request.params["version"]
|
395
396
|
options[:expires_in] = expires_in(request) if request.params["expires_at"]
|
396
397
|
|
397
398
|
derivation = uploaded_file.derivation(name, *args, **options)
|
@@ -475,9 +476,9 @@ class Shrine
|
|
475
476
|
file_response(derivative, env)
|
476
477
|
end
|
477
478
|
|
478
|
-
# Generates a Rack response triple from a local file
|
479
|
-
#
|
480
|
-
#
|
479
|
+
# Generates a Rack response triple from a local file. Fills in
|
480
|
+
# `Content-Type` and `Content-Disposition` response headers from derivation
|
481
|
+
# options and file extension of the derivation result.
|
481
482
|
def file_response(file, env)
|
482
483
|
response = rack_file_response(file.path, env)
|
483
484
|
|
@@ -511,7 +512,7 @@ class Shrine
|
|
511
512
|
end
|
512
513
|
|
513
514
|
if upload_redirect
|
514
|
-
redirect_url = uploaded_file.url(upload_redirect_url_options)
|
515
|
+
redirect_url = uploaded_file.url(**upload_redirect_url_options)
|
515
516
|
|
516
517
|
[302, { "Location" => redirect_url }, []]
|
517
518
|
else
|
@@ -528,10 +529,14 @@ class Shrine
|
|
528
529
|
end
|
529
530
|
end
|
530
531
|
|
531
|
-
# We call `Rack::
|
532
|
+
# We call `Rack::Files` with no default `Content-Type`, and make sure we
|
532
533
|
# stay compatible with both Rack 2.x and 1.6.x.
|
533
534
|
def rack_file_response(path, env)
|
534
|
-
|
535
|
+
if Rack.release >= "2.1"
|
536
|
+
server = Rack::Files.new("", {}, nil)
|
537
|
+
else
|
538
|
+
server = Rack::File.new("", {}, nil)
|
539
|
+
end
|
535
540
|
|
536
541
|
if Rack.release > "2"
|
537
542
|
server.serving(Rack::Request.new(env), path)
|
@@ -598,7 +603,7 @@ class Shrine
|
|
598
603
|
def instrument_derivation(&block)
|
599
604
|
return yield unless shrine_class.respond_to?(:instrument)
|
600
605
|
|
601
|
-
shrine_class.instrument(:derivation, derivation: derivation, &block)
|
606
|
+
shrine_class.instrument(:derivation, { derivation: derivation }, &block)
|
602
607
|
end
|
603
608
|
|
604
609
|
# Massages the derivation result, ensuring it's opened in binary mode,
|
@@ -734,7 +739,7 @@ class Shrine
|
|
734
739
|
def verify_signature(string, signature)
|
735
740
|
if signature.nil?
|
736
741
|
fail InvalidSignature, "missing \"signature\" param"
|
737
|
-
elsif signature
|
742
|
+
elsif !Rack::Utils.secure_compare(signature, generate_signature(string))
|
738
743
|
fail InvalidSignature, "provided signature does not match the calculated signature"
|
739
744
|
end
|
740
745
|
end
|
@@ -4,8 +4,6 @@ class Shrine
|
|
4
4
|
module Plugins
|
5
5
|
# Documentation can be found on https://shrinerb.com/docs/plugins/derivatives
|
6
6
|
module Derivatives
|
7
|
-
NOOP_PROCESSOR = -> (*) { Hash.new }
|
8
|
-
|
9
7
|
LOG_SUBSCRIBER = -> (event) do
|
10
8
|
Shrine.logger.info "Derivatives (#{event.duration}ms) – #{{
|
11
9
|
processor: event[:processor],
|
@@ -21,7 +19,7 @@ class Shrine
|
|
21
19
|
end
|
22
20
|
|
23
21
|
def self.configure(uploader, log_subscriber: LOG_SUBSCRIBER, **opts)
|
24
|
-
uploader.opts[:derivatives] ||= { processors: {}, storage: proc { store_key } }
|
22
|
+
uploader.opts[:derivatives] ||= { processors: {}, processor_settings: {}, storage: proc { store_key } }
|
25
23
|
uploader.opts[:derivatives].merge!(opts)
|
26
24
|
|
27
25
|
# instrumentation plugin integration
|
@@ -40,8 +38,8 @@ class Shrine
|
|
40
38
|
def define_model_methods(name)
|
41
39
|
super if defined?(super)
|
42
40
|
|
43
|
-
define_method(:"#{name}_derivatives!") do |*args|
|
44
|
-
send(:"#{name}_attacher").create_derivatives(*args)
|
41
|
+
define_method(:"#{name}_derivatives!") do |*args, **options|
|
42
|
+
send(:"#{name}_attacher").create_derivatives(*args, **options)
|
45
43
|
end
|
46
44
|
end
|
47
45
|
end
|
@@ -52,20 +50,37 @@ class Shrine
|
|
52
50
|
# Attacher.derivatives_processor :thumbnails do |original|
|
53
51
|
# # ...
|
54
52
|
# end
|
55
|
-
|
53
|
+
#
|
54
|
+
# By default, Shrine will convert the source IO object into a file
|
55
|
+
# before it's passed to the processor block. You can set `download:
|
56
|
+
# false` to pass the source IO object to the processor block as is.
|
57
|
+
#
|
58
|
+
# Attacher.derivatives_processor :thumbnails, download: false do |original|
|
59
|
+
# # ...
|
60
|
+
# end
|
61
|
+
#
|
62
|
+
# This can be useful if you'd like to defer or avoid a possibly
|
63
|
+
# expensive download operation for processor logic that does not
|
64
|
+
# require it.
|
65
|
+
def derivatives_processor(name = :default, download: true, &block)
|
56
66
|
if block
|
57
|
-
shrine_class.
|
67
|
+
shrine_class.derivatives_options[:processors][name.to_sym] = block
|
68
|
+
shrine_class.derivatives_options[:processor_settings][name.to_sym] = { download: download }
|
58
69
|
else
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
fail Error, "derivatives processor #{name.inspect} not registered" unless processor
|
63
|
-
|
64
|
-
processor
|
70
|
+
shrine_class.derivatives_options[:processors].fetch(name.to_sym) do
|
71
|
+
fail Error, "derivatives processor #{name.inspect} not registered" unless name == :default
|
72
|
+
end
|
65
73
|
end
|
66
74
|
end
|
67
75
|
alias derivatives derivatives_processor
|
68
76
|
|
77
|
+
# Returns settings for the given derivatives processor.
|
78
|
+
#
|
79
|
+
# Attacher.derivatives_processor_settings(:thumbnails) #=> { download: true }
|
80
|
+
def derivatives_processor_settings(name)
|
81
|
+
shrine_class.derivatives_options[:processor_settings][name.to_sym] || {}
|
82
|
+
end
|
83
|
+
|
69
84
|
# Specifies default storage to which derivatives will be uploaded.
|
70
85
|
#
|
71
86
|
# Attacher.derivatives_storage :other_store
|
@@ -79,9 +94,9 @@ class Shrine
|
|
79
94
|
# end
|
80
95
|
def derivatives_storage(storage_key = nil, &block)
|
81
96
|
if storage_key || block
|
82
|
-
shrine_class.
|
97
|
+
shrine_class.derivatives_options[:storage] = storage_key || block
|
83
98
|
else
|
84
|
-
shrine_class.
|
99
|
+
shrine_class.derivatives_options[:storage]
|
85
100
|
end
|
86
101
|
end
|
87
102
|
end
|
@@ -147,6 +162,7 @@ class Shrine
|
|
147
162
|
def promote(**options)
|
148
163
|
super
|
149
164
|
promote_derivatives
|
165
|
+
create_derivatives if create_derivatives_on_promote?
|
150
166
|
end
|
151
167
|
|
152
168
|
# Uploads any cached derivatives to permanent storage.
|
@@ -227,8 +243,6 @@ class Shrine
|
|
227
243
|
# hash[:thumb] #=> #<Shrine::UploadedFile>
|
228
244
|
def upload_derivatives(files, **options)
|
229
245
|
map_derivative(files) do |path, file|
|
230
|
-
path = derivative_path(path)
|
231
|
-
|
232
246
|
upload_derivative(path, file, **options)
|
233
247
|
end
|
234
248
|
end
|
@@ -238,6 +252,7 @@ class Shrine
|
|
238
252
|
# hash = attacher.upload_derivative(:thumb, thumb)
|
239
253
|
# hash[:thumb] #=> #<Shrine::UploadedFile>
|
240
254
|
def upload_derivative(path, file, storage: nil, **options)
|
255
|
+
path = derivative_path(path)
|
241
256
|
storage ||= derivative_storage(path)
|
242
257
|
|
243
258
|
file.open if file.is_a?(Tempfile) # refresh file descriptor
|
@@ -269,8 +284,10 @@ class Shrine
|
|
269
284
|
|
270
285
|
source ||= file!
|
271
286
|
|
272
|
-
|
273
|
-
|
287
|
+
processor_settings = self.class.derivatives_processor_settings(processor_name) || {}
|
288
|
+
|
289
|
+
if processor_settings[:download]
|
290
|
+
shrine_class.with_file(source) do |file|
|
274
291
|
_process_derivatives(processor_name, file, **options)
|
275
292
|
end
|
276
293
|
else
|
@@ -374,7 +391,7 @@ class Shrine
|
|
374
391
|
# attacher.derivatives #=> { thumb: #<Shrine::UploadedFile> }
|
375
392
|
def set_derivatives(derivatives)
|
376
393
|
self.derivatives = derivatives
|
377
|
-
set file # trigger model
|
394
|
+
set file # trigger model write
|
378
395
|
derivatives
|
379
396
|
end
|
380
397
|
|
@@ -442,7 +459,7 @@ class Shrine
|
|
442
459
|
# attacher.derivatives #=> { thumb: #<Shrine::UploadedFile> }
|
443
460
|
# attacher.change(file)
|
444
461
|
# attacher.derivatives #=> {}
|
445
|
-
def change(*
|
462
|
+
def change(*)
|
446
463
|
result = super
|
447
464
|
set_derivatives({})
|
448
465
|
result
|
@@ -463,8 +480,8 @@ class Shrine
|
|
463
480
|
# Iterates through nested derivatives and maps results.
|
464
481
|
#
|
465
482
|
# attacher.map_derivative(derivatives) { |path, file| ... }
|
466
|
-
def map_derivative(
|
467
|
-
shrine_class.map_derivative(
|
483
|
+
def map_derivative(derivatives, **options, &block)
|
484
|
+
shrine_class.map_derivative(derivatives, **options, &block)
|
468
485
|
end
|
469
486
|
|
470
487
|
private
|
@@ -473,7 +490,9 @@ class Shrine
|
|
473
490
|
def _process_derivatives(processor_name, source, **options)
|
474
491
|
processor = self.class.derivatives_processor(processor_name)
|
475
492
|
|
476
|
-
|
493
|
+
return {} unless processor
|
494
|
+
|
495
|
+
result = instrument_derivatives(processor_name, source, options) do
|
477
496
|
instance_exec(source, **options, &processor)
|
478
497
|
end
|
479
498
|
|
@@ -485,20 +504,20 @@ class Shrine
|
|
485
504
|
end
|
486
505
|
|
487
506
|
# Sends a `derivatives.shrine` event for instrumentation plugin.
|
488
|
-
def instrument_derivatives(processor_name, processor_options, &block)
|
507
|
+
def instrument_derivatives(processor_name, source, processor_options, &block)
|
489
508
|
return yield unless shrine_class.respond_to?(:instrument)
|
490
509
|
|
491
|
-
shrine_class.instrument(
|
492
|
-
:derivatives,
|
510
|
+
shrine_class.instrument(:derivatives, {
|
493
511
|
processor: processor_name,
|
494
512
|
processor_options: processor_options,
|
495
|
-
|
496
|
-
|
513
|
+
io: source,
|
514
|
+
attacher: self,
|
515
|
+
}, &block)
|
497
516
|
end
|
498
517
|
|
499
518
|
# Returns symbolized array or single key.
|
500
519
|
def derivative_path(path)
|
501
|
-
path = path.map { |key| key.is_a?(String) ? key.to_sym : key }
|
520
|
+
path = Array(path).map { |key| key.is_a?(String) ? key.to_sym : key }
|
502
521
|
path = path.first if path.one?
|
503
522
|
path
|
504
523
|
end
|
@@ -520,6 +539,11 @@ class Shrine
|
|
520
539
|
o2
|
521
540
|
end
|
522
541
|
end
|
542
|
+
|
543
|
+
# Whether to automatically create derivatives on promotion
|
544
|
+
def create_derivatives_on_promote?
|
545
|
+
shrine_class.derivatives_options[:create_on_promote]
|
546
|
+
end
|
523
547
|
end
|
524
548
|
|
525
549
|
module ClassMethods
|
@@ -576,6 +600,11 @@ class Shrine
|
|
576
600
|
yield path, object
|
577
601
|
end
|
578
602
|
end
|
603
|
+
|
604
|
+
# Returns derivatives plugin options.
|
605
|
+
def derivatives_options
|
606
|
+
opts[:derivatives]
|
607
|
+
end
|
579
608
|
end
|
580
609
|
|
581
610
|
module FileMethods
|
@@ -124,6 +124,8 @@ class Shrine
|
|
124
124
|
require "fastimage"
|
125
125
|
|
126
126
|
type = FastImage.type(io)
|
127
|
+
return 'image/svg+xml' if type == :svg
|
128
|
+
|
127
129
|
"image/#{type}" if type
|
128
130
|
end
|
129
131
|
|
@@ -141,7 +143,7 @@ class Shrine
|
|
141
143
|
require "mimemagic"
|
142
144
|
|
143
145
|
mime = MimeMagic.by_magic(io)
|
144
|
-
mime
|
146
|
+
mime&.type
|
145
147
|
end
|
146
148
|
|
147
149
|
def extract_with_marcel(io, options)
|
@@ -158,7 +160,7 @@ class Shrine
|
|
158
160
|
|
159
161
|
if filename = extract_filename(io)
|
160
162
|
mime_type = MIME::Types.of(filename).first
|
161
|
-
mime_type
|
163
|
+
mime_type&.content_type
|
162
164
|
end
|
163
165
|
end
|
164
166
|
|
@@ -167,7 +169,7 @@ class Shrine
|
|
167
169
|
|
168
170
|
if filename = extract_filename(io)
|
169
171
|
info = MiniMime.lookup_by_filename(filename)
|
170
|
-
info
|
172
|
+
info&.content_type
|
171
173
|
end
|
172
174
|
end
|
173
175
|
|
@@ -41,27 +41,27 @@ class Shrine
|
|
41
41
|
end
|
42
42
|
|
43
43
|
# Returns the URL to the attached file.
|
44
|
-
define_method :"#{name}_url" do |*args|
|
45
|
-
send(:"#{name}_attacher").url(*args)
|
44
|
+
define_method :"#{name}_url" do |*args, **options|
|
45
|
+
send(:"#{name}_attacher").url(*args, **options)
|
46
46
|
end
|
47
47
|
|
48
48
|
# Returns an attacher instance.
|
49
49
|
define_method :"#{name}_attacher" do |**options|
|
50
|
-
attachment.send(:attacher, self, options)
|
50
|
+
attachment.send(:attacher, self, **options)
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
54
54
|
# Returns the class attacher instance with loaded entity. It's not
|
55
55
|
# memoized because the entity object could be frozen.
|
56
|
-
def attacher(record, options)
|
57
|
-
attacher = class_attacher(options)
|
56
|
+
def attacher(record, **options)
|
57
|
+
attacher = class_attacher(**options)
|
58
58
|
attacher.load_entity(record, @name)
|
59
59
|
attacher
|
60
60
|
end
|
61
61
|
|
62
62
|
# Creates an instance of the corresponding attacher class with set
|
63
63
|
# name.
|
64
|
-
def class_attacher(options)
|
64
|
+
def class_attacher(**options)
|
65
65
|
attacher = shrine_class::Attacher.new(**@options, **options)
|
66
66
|
attacher.instance_variable_set(:@name, @name)
|
67
67
|
attacher
|
@@ -112,9 +112,15 @@ class Shrine
|
|
112
112
|
# attacher.file #=> #<Shrine::UploadedFile>
|
113
113
|
def reload
|
114
114
|
read
|
115
|
+
@previous = nil
|
115
116
|
self
|
116
117
|
end
|
117
118
|
|
119
|
+
# Loads attachment from the entity attribute.
|
120
|
+
def read
|
121
|
+
load_column(read_attribute)
|
122
|
+
end
|
123
|
+
|
118
124
|
# Returns a hash with entity attribute name and column data.
|
119
125
|
#
|
120
126
|
# attacher.column_values
|
@@ -134,11 +140,6 @@ class Shrine
|
|
134
140
|
|
135
141
|
private
|
136
142
|
|
137
|
-
# Loads attachment from the entity attribute.
|
138
|
-
def read
|
139
|
-
load_column(read_attribute)
|
140
|
-
end
|
141
|
-
|
142
143
|
# Reads value from the entity attribute.
|
143
144
|
def read_attribute
|
144
145
|
record.public_send(attribute)
|