shrine 3.0.1 → 3.3.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/LICENSE.txt +1 -1
- data/README.md +15 -5
- data/doc/advantages.md +33 -16
- data/doc/attacher.md +2 -2
- data/doc/carrierwave.md +78 -34
- data/doc/changing_derivatives.md +39 -39
- data/doc/design.md +134 -85
- data/doc/direct_s3.md +1 -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 +177 -112
- data/doc/metadata.md +79 -43
- data/doc/multiple_files.md +6 -4
- data/doc/paperclip.md +119 -42
- data/doc/plugins/activerecord.md +1 -1
- 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/data_uri.md +2 -2
- data/doc/plugins/default_url.md +6 -3
- data/doc/plugins/derivation_endpoint.md +26 -28
- data/doc/plugins/derivatives.md +238 -171
- data/doc/plugins/determine_mime_type.md +2 -2
- data/doc/plugins/download_endpoint.md +5 -5
- data/doc/plugins/dynamic_storage.md +1 -1
- data/doc/plugins/form_assign.md +5 -5
- data/doc/plugins/included.md +25 -5
- data/doc/plugins/infer_extension.md +11 -2
- data/doc/plugins/instrumentation.md +1 -1
- data/doc/plugins/metadata_attributes.md +22 -10
- data/doc/plugins/mirroring.md +1 -1
- data/doc/plugins/persistence.md +11 -1
- data/doc/plugins/refresh_metadata.md +5 -4
- data/doc/plugins/remote_url.md +8 -3
- data/doc/plugins/remove_invalid.md +9 -1
- data/doc/plugins/signature.md +11 -2
- data/doc/plugins/store_dimensions.md +12 -2
- data/doc/plugins/type_predicates.md +96 -0
- data/doc/plugins/upload_endpoint.md +7 -11
- 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/validation_helpers.md +3 -3
- data/doc/plugins/versions.md +7 -7
- data/doc/processing.md +290 -127
- data/doc/refile.md +39 -18
- data/doc/release_notes/2.19.0.md +1 -1
- 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.0.1.md +4 -0
- data/doc/release_notes/3.1.0.md +73 -0
- 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/securing_uploads.md +3 -3
- data/doc/storage/file_system.md +1 -1
- data/doc/storage/memory.md +19 -0
- data/doc/storage/s3.md +105 -82
- data/doc/testing.md +2 -2
- data/doc/upgrading_to_3.md +97 -49
- data/doc/validation.md +3 -2
- data/lib/shrine.rb +8 -8
- data/lib/shrine/attacher.rb +24 -14
- data/lib/shrine/attachment.rb +5 -5
- data/lib/shrine/plugins.rb +22 -0
- data/lib/shrine/plugins/activerecord.rb +1 -1
- data/lib/shrine/plugins/add_metadata.rb +18 -7
- data/lib/shrine/plugins/backgrounding.rb +2 -2
- data/lib/shrine/plugins/default_storage.rb +6 -6
- data/lib/shrine/plugins/default_url.rb +1 -1
- data/lib/shrine/plugins/derivation_endpoint.rb +12 -7
- data/lib/shrine/plugins/derivatives.rb +61 -29
- data/lib/shrine/plugins/determine_mime_type.rb +3 -3
- data/lib/shrine/plugins/entity.rb +6 -6
- 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/signature.rb +7 -6
- data/lib/shrine/plugins/store_dimensions.rb +22 -11
- 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/uploaded_file.rb +0 -1
- data/lib/shrine/version.rb +2 -2
- data/shrine.gemspec +7 -8
- metadata +25 -31
data/doc/plugins/activerecord.md
CHANGED
data/doc/plugins/add_metadata.md
CHANGED
@@ -2,76 +2,130 @@
|
|
2
2
|
title: Add Metadata
|
3
3
|
---
|
4
4
|
|
5
|
-
The [`add_metadata`][add_metadata] plugin
|
6
|
-
|
5
|
+
The [`add_metadata`][add_metadata] plugin allows adding custom metadata to
|
6
|
+
uploaded files.
|
7
7
|
|
8
8
|
```rb
|
9
|
-
plugin :add_metadata
|
9
|
+
Shrine.plugin :add_metadata
|
10
|
+
```
|
11
|
+
|
12
|
+
## Metadata block
|
13
|
+
|
14
|
+
The `Shrine.add_metadata` method allows you to register a block that will get
|
15
|
+
executed on upload, where you can return custom metadata:
|
16
|
+
|
17
|
+
```rb
|
18
|
+
require "pdf-reader" # https://github.com/yob/pdf-reader
|
10
19
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
{}
|
20
|
+
class PdfUploader < Shrine
|
21
|
+
add_metadata :page_count do |io|
|
22
|
+
reader = PDF::Reader.new(io)
|
23
|
+
reader.page_count
|
16
24
|
end
|
17
25
|
end
|
18
26
|
```
|
19
27
|
|
20
|
-
The above will add
|
21
|
-
reader method on `Shrine::UploadedFile`.
|
28
|
+
The above will add `page_count` key to the metadata hash, and also create the
|
29
|
+
`#page_count` reader method on the `Shrine::UploadedFile`.
|
22
30
|
|
23
31
|
```rb
|
24
|
-
|
32
|
+
uploaded_file.metadata["page_count"] #=> 30
|
25
33
|
# or
|
26
|
-
|
34
|
+
uploaded_file.page_count #=> 30
|
35
|
+
```
|
36
|
+
|
37
|
+
### Skipping nil values
|
38
|
+
|
39
|
+
By default, if your block returns `nil` then the `nil` value will be stored into
|
40
|
+
metadata. If you do not want to store anything when your block returns nil, you
|
41
|
+
can use the `skip_nil: true` option:
|
42
|
+
|
43
|
+
```rb
|
44
|
+
class PdfUploader < Shrine
|
45
|
+
add_metadata :pages, skip_nil: true do |io|
|
46
|
+
if is_pdf?(io)
|
47
|
+
reader = PDF::Reader.new(io)
|
48
|
+
reader.page_count
|
49
|
+
else
|
50
|
+
# If this is not a PDF, then the pages metadata will not be stored
|
51
|
+
nil
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
27
55
|
```
|
28
56
|
|
29
|
-
|
57
|
+
### Multiple values
|
30
58
|
|
31
59
|
You can also extract multiple metadata values at once, by using `add_metadata`
|
32
60
|
without an argument and returning a hash of metadata.
|
33
61
|
|
34
62
|
```rb
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
63
|
+
require "exif" # https://github.com/tonytonyjan/exif
|
64
|
+
|
65
|
+
class ImageUploader < Shrine
|
66
|
+
add_metadata do |io|
|
67
|
+
begin
|
68
|
+
data = Exif::Data.new(io)
|
69
|
+
rescue Exif::NotReadable # not a valid image
|
70
|
+
next {}
|
71
|
+
end
|
72
|
+
|
73
|
+
{ "date_time" => data.date_time,
|
74
|
+
"flash" => data.flash,
|
75
|
+
"focal_length" => data.focal_length,
|
76
|
+
"exposure_time" => data.exposure_time }
|
40
77
|
end
|
41
|
-
|
42
|
-
{ date_time: data.date_time,
|
43
|
-
flash: data.flash,
|
44
|
-
focal_length: data.focal_length,
|
45
|
-
exposure_time: data.exposure_time }
|
46
78
|
end
|
47
79
|
```
|
80
|
+
```rb
|
81
|
+
uploaded_file.metadata #=>
|
82
|
+
# {
|
83
|
+
# ...
|
84
|
+
# "date_time" => "2019:07:20 16:16:08",
|
85
|
+
# "flash" => 16,
|
86
|
+
# "focal_length" => 26/1,
|
87
|
+
# "exposure_time" => 1/500,
|
88
|
+
# }
|
89
|
+
```
|
48
90
|
|
49
91
|
In this case Shrine won't automatically create reader methods for the extracted
|
50
|
-
metadata
|
51
|
-
`#metadata_method`.
|
92
|
+
metadata, but you can create them via `Shrine.metadata_method`:
|
52
93
|
|
53
94
|
```rb
|
54
|
-
|
95
|
+
class ImageUploader < Shrine
|
96
|
+
# ...
|
97
|
+
metadata_method :date_time, :flash
|
98
|
+
end
|
99
|
+
```
|
100
|
+
```rb
|
101
|
+
uploaded_file.date_time #=> "2019:07:20 16:16:08"
|
102
|
+
uploaded_file.flash #=> 16
|
55
103
|
```
|
56
104
|
|
57
|
-
|
105
|
+
### Ensuring file
|
58
106
|
|
59
107
|
The `io` might not always be a file object, so if you're using an analyzer
|
60
108
|
which requires the source file to be on disk, you can use `Shrine.with_file` to
|
61
109
|
ensure you have a file object.
|
62
110
|
|
63
111
|
```rb
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
112
|
+
require "streamio-ffmpeg" # https://github.com/streamio/streamio-ffmpeg
|
113
|
+
|
114
|
+
class VideoUploader < Shrine
|
115
|
+
add_metadata do |io|
|
116
|
+
movie = Shrine.with_file(io) do |file|
|
117
|
+
FFMPEG::Movie.new(file.path)
|
118
|
+
end
|
119
|
+
|
120
|
+
{ "duration" => movie.duration,
|
121
|
+
"bitrate" => movie.bitrate,
|
122
|
+
"resolution" => movie.resolution,
|
123
|
+
"frame_rate" => movie.frame_rate }
|
124
|
+
end
|
71
125
|
end
|
72
126
|
```
|
73
127
|
|
74
|
-
|
128
|
+
### Uploader options
|
75
129
|
|
76
130
|
Uploader options are also yielded to the block, you can access them for more
|
77
131
|
context:
|
@@ -89,6 +143,8 @@ add_metadata do |io, **options|
|
|
89
143
|
end
|
90
144
|
```
|
91
145
|
|
146
|
+
#### Metadata
|
147
|
+
|
92
148
|
The `:metadata` option holds metadata that was extracted so far:
|
93
149
|
|
94
150
|
```rb
|
@@ -116,4 +172,25 @@ add_metadata :bar do |io, metadata:, **|
|
|
116
172
|
end
|
117
173
|
```
|
118
174
|
|
175
|
+
## Updating metadata
|
176
|
+
|
177
|
+
If you just wish to add some custom metadata to existing uploads, you can do it
|
178
|
+
with `UploadedFile#add_metadata` (and write the changes back to the model):
|
179
|
+
|
180
|
+
```rb
|
181
|
+
attacher.file.add_metadata("foo" => "bar")
|
182
|
+
attacher.write # write changes to the model attribute
|
183
|
+
|
184
|
+
attacher.file.metadata #=> { ..., "foo" => "bar" }
|
185
|
+
```
|
186
|
+
|
187
|
+
You can also use the `Attacher#add_metadata` shorthand, which also takes care
|
188
|
+
of syncing the model:
|
189
|
+
|
190
|
+
```rb
|
191
|
+
attacher.add_metadata("foo" => "bar")
|
192
|
+
|
193
|
+
attacher.file.metadata #=> { ..., "foo" => "bar" }
|
194
|
+
```
|
195
|
+
|
119
196
|
[add_metadata]: https://github.com/shrinerb/shrine/blob/master/lib/shrine/plugins/add_metadata.rb
|
@@ -3,14 +3,48 @@ title: Atomic Helpers
|
|
3
3
|
---
|
4
4
|
|
5
5
|
The [`atomic_helpers`][atomic_helpers] plugin provides API for retrieving and
|
6
|
-
persisting attachments in a concurrency-safe way, which is useful
|
7
|
-
the `backgrounding` plugin. The database plugins (`activerecord`
|
8
|
-
implement atomic promotion and atomic persistence on top of this
|
6
|
+
persisting attachments in a concurrency-safe way, which is especially useful
|
7
|
+
when using the `backgrounding` plugin. The database plugins (`activerecord`
|
8
|
+
and `sequel`) implement atomic promotion and atomic persistence on top of this
|
9
|
+
plugin.
|
9
10
|
|
10
11
|
```rb
|
11
12
|
plugin :atomic_helpers
|
12
13
|
```
|
13
14
|
|
15
|
+
## Problem Statement
|
16
|
+
|
17
|
+
What happens if two different processors (web workers, background jobs,
|
18
|
+
command-line executions, whatever) try to edit a shrine attachment
|
19
|
+
concurrently? The kinds of edits typically made include: "promoting a file",
|
20
|
+
moving it to a different storage and persisting that change in the model;
|
21
|
+
adding or changing a derivative; adding or changing a metadata element.
|
22
|
+
|
23
|
+
There are two main categories of "race condition":
|
24
|
+
|
25
|
+
1. The file could be switched out from under you. If you were promoting a file,
|
26
|
+
but some other process has *changed* the attachment, you don't want to
|
27
|
+
overwrite it with the promomoted version of the *prior* attacchment. Likewise,
|
28
|
+
if you were adding metadata or a derivative, they would be corresponding to a
|
29
|
+
certain attachment, and you don't want to accidentally add them to a now changed
|
30
|
+
attacchment for which they are inappropriate.
|
31
|
+
|
32
|
+
2. Overwriting each other's edits. Since all shrine (meta)data is stored in a
|
33
|
+
single JSON hash, standard implementations will write the entire JSON hash at
|
34
|
+
once to a rdbms column or other store. If two processes both read in the hash,
|
35
|
+
make a change to different keys in it, and then write it back out, the second
|
36
|
+
process to write will 'win' and overwrite changes made by the first.
|
37
|
+
|
38
|
+
The atomic helpers give you tools to avoid both of these sorts of race
|
39
|
+
conditions, under conditions of concurrent editing.
|
40
|
+
|
41
|
+
## High-level ORM helpers
|
42
|
+
|
43
|
+
If you are using the `sequel` or `activerecord` plugins, they give you two
|
44
|
+
higher-level helpers: `atomic_persist` and `atomic_promote`. See the
|
45
|
+
[persistence] documentation for more.
|
46
|
+
|
47
|
+
|
14
48
|
## Retrieving
|
15
49
|
|
16
50
|
The `Attacher.retrieve` method provided by the plugin instantiates an attacher
|
@@ -177,3 +211,7 @@ end
|
|
177
211
|
```
|
178
212
|
|
179
213
|
[atomic_helpers]: https://github.com/shrinerb/shrine/blob/master/lib/shrine/plugins/atomic_helpers.rb
|
214
|
+
|
215
|
+
[persistence]: https://shrinerb.com/docs/plugins/persistence
|
216
|
+
|
217
|
+
[backgrounding]: https://shrinerb.com/docs/plugins/backgrounding
|
@@ -187,12 +187,22 @@ and make the execution synchronous, you can override them on the attacher level
|
|
187
187
|
and call the default behaviour:
|
188
188
|
|
189
189
|
```rb
|
190
|
-
photo.image_attacher.promote_block
|
191
|
-
photo.image_attacher.destroy_block
|
190
|
+
photo.image_attacher.promote_block { promote } # promote synchronously
|
191
|
+
photo.image_attacher.destroy_block { destroy } # destroy synchronously
|
192
192
|
|
193
193
|
# ... now promotion and deletion will be synchronous ...
|
194
194
|
```
|
195
195
|
|
196
|
+
You can also do this on the class level if you want to disable backgrounding
|
197
|
+
that was set up by a superclass:
|
198
|
+
|
199
|
+
```rb
|
200
|
+
class MyUploader < Shrine
|
201
|
+
Attacher.promote_block { promote } # promote synchronously
|
202
|
+
Attacher.destroy_block { destroy } # destroy synchronously
|
203
|
+
end
|
204
|
+
```
|
205
|
+
|
196
206
|
[backgrounding]: https://github.com/shrinerb/shrine/blob/master/lib/shrine/plugins/backgrounding.rb
|
197
207
|
[derivatives]: https://shrinerb.com/docs/plugins/derivatives
|
198
208
|
[atomic_helpers]: https://shrinerb.com/docs/plugins/atomic_helpers
|
data/doc/plugins/column.md
CHANGED
@@ -66,23 +66,48 @@ If you want to load attachment from a Hash, use `Attacher.from_data` or
|
|
66
66
|
|
67
67
|
## Serializer
|
68
68
|
|
69
|
-
By default the `JSON` standard library is used
|
70
|
-
|
71
|
-
|
69
|
+
By default, the `JSON` standard library is used for serializing hash data. With
|
70
|
+
the [`model`][model] and [`entity`][entity] plugin, the data is serialized
|
71
|
+
before writing to and deserialized after reading from the data attribute.
|
72
|
+
|
73
|
+
You can also use your own serializer via the `:serializer` option. The
|
74
|
+
serializer object needs to implement `#dump` and `#load` methods:
|
75
|
+
|
76
|
+
```rb
|
77
|
+
class MyDataSerializer
|
78
|
+
def self.dump(data)
|
79
|
+
data #=> { "id" => "...", "storage" => "...", "metadata" => { ... } }
|
80
|
+
|
81
|
+
JSON.generate(data) # serialize data, e.g. into JSON
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.load(data)
|
85
|
+
data #=> '{"id":"...", "storage":"...", "metadata": {...}}'
|
86
|
+
|
87
|
+
JSON.parse(data) # deserialize data, e.g. from JSON
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
plugin :column, serializer: MyDataSerializer
|
92
|
+
```
|
93
|
+
|
94
|
+
Some serialization libraries such as [Oj] and [MessagePack] already implement
|
95
|
+
this interface, which simplifies the configuration:
|
72
96
|
|
73
97
|
```rb
|
74
|
-
require "oj"
|
98
|
+
require "oj" # https://github.com/ohler55/oj
|
75
99
|
|
76
|
-
plugin :column, serializer: Oj
|
100
|
+
plugin :column, serializer: Oj
|
77
101
|
```
|
78
102
|
|
79
|
-
If you want to disable serialization, you can set
|
103
|
+
If you want to disable serialization and work with hashes directly, you can set
|
104
|
+
`:serializer` to `nil`:
|
80
105
|
|
81
106
|
```rb
|
82
107
|
plugin :column, serializer: nil # disable serialization
|
83
108
|
```
|
84
109
|
|
85
|
-
|
110
|
+
The serializer can also be changed for a particular attacher instance:
|
86
111
|
|
87
112
|
```rb
|
88
113
|
Shrine::Attacher.new(column_serializer: Oj) # use custom serializer
|
@@ -90,3 +115,7 @@ Shrine::Attacher.new(column_serializer: nil) # disable serialization
|
|
90
115
|
```
|
91
116
|
|
92
117
|
[column]: https://github.com/shrinerb/shrine/blob/master/lib/shrine/plugins/column.rb
|
118
|
+
[model]: https://shrinerb.com/docs/plugins/model
|
119
|
+
[entity]: https://shrinerb.com/docs/plugins/entity
|
120
|
+
[Oj]: https://github.com/ohler55/oj
|
121
|
+
[MessagePack]: https://github.com/msgpack/msgpack-ruby
|
data/doc/plugins/data_uri.md
CHANGED
@@ -123,7 +123,7 @@ payload:
|
|
123
123
|
|
124
124
|
A default log subscriber is added as well which logs these events:
|
125
125
|
|
126
|
-
```
|
126
|
+
```
|
127
127
|
Data URI (5ms) – {:uploader=>Shrine}
|
128
128
|
```
|
129
129
|
|
@@ -134,7 +134,7 @@ plugin :data_uri, log_subscriber: -> (event) {
|
|
134
134
|
Shrine.logger.info JSON.generate(name: event.name, duration: event.duration, uploader: event[:uploader])
|
135
135
|
}
|
136
136
|
```
|
137
|
-
```
|
137
|
+
```
|
138
138
|
{"name":"data_uri","duration":5,"uploader":"Shrine"}
|
139
139
|
```
|
140
140
|
|
data/doc/plugins/default_url.md
CHANGED
@@ -8,7 +8,7 @@ returned when there is no attached file.
|
|
8
8
|
```rb
|
9
9
|
plugin :default_url
|
10
10
|
|
11
|
-
Attacher.default_url do
|
11
|
+
Attacher.default_url do |**options|
|
12
12
|
"/#{name}/missing.jpg"
|
13
13
|
end
|
14
14
|
```
|
@@ -28,7 +28,7 @@ Any URL options passed will be available in the default URL block:
|
|
28
28
|
attacher.url(foo: "bar")
|
29
29
|
```
|
30
30
|
```rb
|
31
|
-
Attacher.default_url do
|
31
|
+
Attacher.default_url do |**options|
|
32
32
|
options #=> { foo: "bar" }
|
33
33
|
end
|
34
34
|
```
|
@@ -37,12 +37,15 @@ The default URL block is evaluated in the context of an instance of
|
|
37
37
|
`Shrine::Attacher`.
|
38
38
|
|
39
39
|
```rb
|
40
|
-
Attacher.default_url do
|
40
|
+
Attacher.default_url do |**options|
|
41
41
|
self #=> #<Shrine::Attacher>
|
42
42
|
|
43
|
+
file #=> #<Shrine::UploadedFile>
|
43
44
|
name #=> :avatar
|
44
45
|
record #=> #<User>
|
45
46
|
context #=> { ... }
|
47
|
+
|
48
|
+
# ...
|
46
49
|
end
|
47
50
|
```
|
48
51
|
|
@@ -68,7 +68,7 @@ generates an URL consisting of the configured [path prefix](#prefix),
|
|
68
68
|
derivation name and arguments, serialized uploaded file, and an URL signature
|
69
69
|
generated using the configured secret key:
|
70
70
|
|
71
|
-
```
|
71
|
+
```
|
72
72
|
/ derivations/image / thumbnail / 600/400 / eyJmZvbyIb3JhZ2UiOiJzdG9yZSJ9 ? signature=...
|
73
73
|
└──── prefix ─────┘ └── name ──┘ └─ args ─┘ └─── serialized source file ───┘
|
74
74
|
```
|
@@ -197,7 +197,8 @@ Rails.application.routes.draw do
|
|
197
197
|
end
|
198
198
|
end
|
199
199
|
end
|
200
|
-
|
200
|
+
```
|
201
|
+
```rb
|
201
202
|
# app/controllers/photos_controller.rb
|
202
203
|
class PhotosController < ApplicationController
|
203
204
|
def thumbnail
|
@@ -483,32 +484,27 @@ such as AWS S3 or Google Cloud Storage.
|
|
483
484
|
### Deleting derivatives
|
484
485
|
|
485
486
|
When the original attachment is deleted, its uploaded derivatives will not be
|
486
|
-
automatically deleted, you will need to do the deletion manually.
|
487
|
-
|
488
|
-
`Attacher#destroy`.
|
487
|
+
automatically deleted, you will need to do the deletion manually. If you're
|
488
|
+
using [backgrounding], you can do this in your `DestroyJob`.
|
489
489
|
|
490
|
-
|
490
|
+
If your storage implements `#delete_prefixed`, and you're using the default
|
491
|
+
[`:upload_location`](#upload-location), you can delete the directory containing
|
492
|
+
derivatives:
|
491
493
|
|
492
494
|
```rb
|
493
|
-
class
|
494
|
-
|
495
|
-
|
496
|
-
super
|
495
|
+
class DestroyJob < ActiveJob::Base
|
496
|
+
def perform(attacher_class, data)
|
497
|
+
# ... destroy attached file ...
|
497
498
|
|
498
|
-
|
499
|
-
|
499
|
+
derivatives_directory = attacher.file.id + "/"
|
500
|
+
storage = attacher.store.storage
|
500
501
|
|
501
|
-
|
502
|
-
end
|
502
|
+
storage.delete_prefixed(derivatives_directory)
|
503
503
|
end
|
504
504
|
end
|
505
505
|
```
|
506
506
|
|
507
|
-
|
508
|
-
and that you're using default [`:upload_location`](#upload-location).
|
509
|
-
|
510
|
-
Alternatively, you can delete each derivative individually using
|
511
|
-
`Derivation#delete`:
|
507
|
+
Alternatively, you can delete each derivative individually:
|
512
508
|
|
513
509
|
```rb
|
514
510
|
class ImageUploader < Shrine
|
@@ -518,14 +514,15 @@ class ImageUploader < Shrine
|
|
518
514
|
[:thumbnail, 400, 300],
|
519
515
|
...
|
520
516
|
]
|
517
|
+
end
|
518
|
+
```
|
519
|
+
```rb
|
520
|
+
class DestroyJob < ActiveJob::Base
|
521
|
+
def perform(attacher_class, data)
|
522
|
+
# ... destroy attached file ...
|
521
523
|
|
522
|
-
|
523
|
-
|
524
|
-
super
|
525
|
-
|
526
|
-
DERIVATIONS.each do |args|
|
527
|
-
file.derivation(*args).delete
|
528
|
-
end
|
524
|
+
attacher.shrine_class::DERIVATIONS.each do |args|
|
525
|
+
attacher.file.derivation(*args).delete
|
529
526
|
end
|
530
527
|
end
|
531
528
|
end
|
@@ -830,7 +827,7 @@ following payload:
|
|
830
827
|
|
831
828
|
A default log subscriber is added as well which logs these events:
|
832
829
|
|
833
|
-
```
|
830
|
+
```
|
834
831
|
Derivation (492ms) – {:name=>:thumbnail, :args=>[600, 600], :uploader=>Shrine}
|
835
832
|
```
|
836
833
|
|
@@ -846,7 +843,7 @@ plugin :derivation_endpoint, log_subscriber: -> (event) {
|
|
846
843
|
)
|
847
844
|
}
|
848
845
|
```
|
849
|
-
```
|
846
|
+
```
|
850
847
|
{"name":"derivation","duration":492,"name":"thumbnail","args":[600,600],"uploader":"Shrine"}
|
851
848
|
```
|
852
849
|
|
@@ -861,3 +858,4 @@ plugin :derivation_endpoint, log_subscriber: nil
|
|
861
858
|
[`Content-Type`]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type
|
862
859
|
[`Content-Disposition`]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition
|
863
860
|
[`Cache-Control`]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control
|
861
|
+
[backgrounding]: https://shrinerb.com/docs/plugins/backgrounding
|