shrine 3.0.1 → 3.3.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.
- 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
|