shrine 3.0.1 → 3.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +82 -0
  3. data/LICENSE.txt +1 -1
  4. data/README.md +15 -5
  5. data/doc/advantages.md +33 -16
  6. data/doc/attacher.md +2 -2
  7. data/doc/carrierwave.md +78 -34
  8. data/doc/changing_derivatives.md +39 -39
  9. data/doc/design.md +134 -85
  10. data/doc/direct_s3.md +1 -0
  11. data/doc/external/articles.md +57 -45
  12. data/doc/external/extensions.md +41 -35
  13. data/doc/external/misc.md +23 -8
  14. data/doc/getting_started.md +177 -112
  15. data/doc/metadata.md +79 -43
  16. data/doc/multiple_files.md +6 -4
  17. data/doc/paperclip.md +119 -42
  18. data/doc/plugins/activerecord.md +1 -1
  19. data/doc/plugins/add_metadata.md +112 -35
  20. data/doc/plugins/atomic_helpers.md +41 -3
  21. data/doc/plugins/backgrounding.md +12 -2
  22. data/doc/plugins/column.md +36 -7
  23. data/doc/plugins/data_uri.md +2 -2
  24. data/doc/plugins/default_url.md +6 -3
  25. data/doc/plugins/derivation_endpoint.md +26 -28
  26. data/doc/plugins/derivatives.md +238 -171
  27. data/doc/plugins/determine_mime_type.md +2 -2
  28. data/doc/plugins/download_endpoint.md +5 -5
  29. data/doc/plugins/dynamic_storage.md +1 -1
  30. data/doc/plugins/form_assign.md +5 -5
  31. data/doc/plugins/included.md +25 -5
  32. data/doc/plugins/infer_extension.md +11 -2
  33. data/doc/plugins/instrumentation.md +1 -1
  34. data/doc/plugins/metadata_attributes.md +22 -10
  35. data/doc/plugins/mirroring.md +1 -1
  36. data/doc/plugins/persistence.md +11 -1
  37. data/doc/plugins/refresh_metadata.md +5 -4
  38. data/doc/plugins/remote_url.md +8 -3
  39. data/doc/plugins/remove_invalid.md +9 -1
  40. data/doc/plugins/signature.md +11 -2
  41. data/doc/plugins/store_dimensions.md +12 -2
  42. data/doc/plugins/type_predicates.md +96 -0
  43. data/doc/plugins/upload_endpoint.md +7 -11
  44. data/doc/plugins/upload_options.md +1 -1
  45. data/doc/plugins/url_options.md +4 -4
  46. data/doc/plugins/validation.md +14 -4
  47. data/doc/plugins/validation_helpers.md +3 -3
  48. data/doc/plugins/versions.md +7 -7
  49. data/doc/processing.md +290 -127
  50. data/doc/refile.md +39 -18
  51. data/doc/release_notes/2.19.0.md +1 -1
  52. data/doc/release_notes/2.8.0.md +1 -1
  53. data/doc/release_notes/3.0.0.md +1 -1
  54. data/doc/release_notes/3.0.1.md +4 -0
  55. data/doc/release_notes/3.1.0.md +73 -0
  56. data/doc/release_notes/3.2.0.md +96 -0
  57. data/doc/release_notes/3.2.1.md +31 -0
  58. data/doc/release_notes/3.2.2.md +14 -0
  59. data/doc/release_notes/3.3.0.md +105 -0
  60. data/doc/securing_uploads.md +3 -3
  61. data/doc/storage/file_system.md +1 -1
  62. data/doc/storage/memory.md +19 -0
  63. data/doc/storage/s3.md +105 -82
  64. data/doc/testing.md +2 -2
  65. data/doc/upgrading_to_3.md +97 -49
  66. data/doc/validation.md +3 -2
  67. data/lib/shrine.rb +8 -8
  68. data/lib/shrine/attacher.rb +24 -14
  69. data/lib/shrine/attachment.rb +5 -5
  70. data/lib/shrine/plugins.rb +22 -0
  71. data/lib/shrine/plugins/activerecord.rb +1 -1
  72. data/lib/shrine/plugins/add_metadata.rb +18 -7
  73. data/lib/shrine/plugins/backgrounding.rb +2 -2
  74. data/lib/shrine/plugins/default_storage.rb +6 -6
  75. data/lib/shrine/plugins/default_url.rb +1 -1
  76. data/lib/shrine/plugins/derivation_endpoint.rb +12 -7
  77. data/lib/shrine/plugins/derivatives.rb +61 -29
  78. data/lib/shrine/plugins/determine_mime_type.rb +3 -3
  79. data/lib/shrine/plugins/entity.rb +6 -6
  80. data/lib/shrine/plugins/mirroring.rb +8 -8
  81. data/lib/shrine/plugins/model.rb +3 -3
  82. data/lib/shrine/plugins/presign_endpoint.rb +16 -4
  83. data/lib/shrine/plugins/pretty_location.rb +1 -1
  84. data/lib/shrine/plugins/processing.rb +1 -1
  85. data/lib/shrine/plugins/refresh_metadata.rb +2 -2
  86. data/lib/shrine/plugins/remote_url.rb +3 -3
  87. data/lib/shrine/plugins/remove_attachment.rb +5 -0
  88. data/lib/shrine/plugins/remove_invalid.rb +10 -5
  89. data/lib/shrine/plugins/sequel.rb +1 -1
  90. data/lib/shrine/plugins/signature.rb +7 -6
  91. data/lib/shrine/plugins/store_dimensions.rb +22 -11
  92. data/lib/shrine/plugins/type_predicates.rb +113 -0
  93. data/lib/shrine/plugins/upload_endpoint.rb +10 -5
  94. data/lib/shrine/plugins/upload_options.rb +2 -2
  95. data/lib/shrine/plugins/url_options.rb +2 -2
  96. data/lib/shrine/plugins/validation.rb +9 -7
  97. data/lib/shrine/storage/linter.rb +4 -4
  98. data/lib/shrine/storage/memory.rb +5 -3
  99. data/lib/shrine/storage/s3.rb +117 -38
  100. data/lib/shrine/uploaded_file.rb +0 -1
  101. data/lib/shrine/version.rb +2 -2
  102. data/shrine.gemspec +7 -8
  103. metadata +25 -31
@@ -158,7 +158,7 @@ end
158
158
  ```
159
159
  ```yml
160
160
  en:
161
- activerecord
161
+ activerecord:
162
162
  errors:
163
163
  models:
164
164
  photo:
@@ -2,76 +2,130 @@
2
2
  title: Add Metadata
3
3
  ---
4
4
 
5
- The [`add_metadata`][add_metadata] plugin provides a convenient method for
6
- extracting and adding custom metadata values.
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
- add_metadata :exif do |io|
12
- begin
13
- Exif::Data.new(io).to_h
14
- rescue Exif::NotReadable # not a valid image
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 "exif" to the metadata hash, and also create the `#exif`
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
- image.metadata["exif"]
32
+ uploaded_file.metadata["page_count"] #=> 30
25
33
  # or
26
- image.exif
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
- ## Multiple values
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
- add_metadata do |io|
36
- begin
37
- data = Exif::Data.new(io)
38
- rescue Exif::NotReadable # not a valid image
39
- next {}
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 on Shrine::UploadedFile, but you can create them via
51
- `#metadata_method`.
92
+ metadata, but you can create them via `Shrine.metadata_method`:
52
93
 
53
94
  ```rb
54
- metadata_method :date_time, :flash
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
- ## Ensuring file
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
- add_metadata do |io|
65
- movie = Shrine.with_file(io) { |file| FFMPEG::Movie.new(file.path) }
66
-
67
- { "duration" => movie.duration,
68
- "bitrate" => movie.bitrate,
69
- "resolution" => movie.resolution,
70
- "frame_rate" => movie.frame_rate }
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
- ## Uploader options
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 when using
7
- the `backgrounding` plugin. The database plugins (`activerecord` and `sequel`)
8
- implement atomic promotion and atomic persistence on top of this plugin.
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(&:promote)
191
- photo.image_attacher.destroy_block(&:destroy)
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
@@ -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 as the serializer, but you can
70
- use your own serializer. The serializer object needs to implement `#dump` and
71
- `#load` methods.
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 # use custom serializer
100
+ plugin :column, serializer: Oj
77
101
  ```
78
102
 
79
- If you want to disable serialization, you can set serializer to `nil`.
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
- You can also change the serializer on the attacher level:
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
@@ -123,7 +123,7 @@ payload:
123
123
 
124
124
  A default log subscriber is added as well which logs these events:
125
125
 
126
- ```plaintext
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
- ```plaintext
137
+ ```
138
138
  {"name":"data_uri","duration":5,"uploader":"Shrine"}
139
139
  ```
140
140
 
@@ -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 |options|
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 |options|
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 |options|
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
- ```plaintext
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. To ensure
487
- this gets called both on destroying and replacing, you can add that code to
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
- The easiest way is to delete the directory containing your derivatives:
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 ImageUploader < Shrine
494
- class Attacher
495
- def destroy(*args)
496
- super
495
+ class DestroyJob < ActiveJob::Base
496
+ def perform(attacher_class, data)
497
+ # ... destroy attached file ...
497
498
 
498
- derivatives_directory = file.id
499
- storage = store.storage
499
+ derivatives_directory = attacher.file.id + "/"
500
+ storage = attacher.store.storage
500
501
 
501
- storage.delete_prefixed(derivatives_directory)
502
- end
502
+ storage.delete_prefixed(derivatives_directory)
503
503
  end
504
504
  end
505
505
  ```
506
506
 
507
- This is under the assumption that your storage implements `#delete_prefixed`
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
- class Attacher
523
- def destroy(*args)
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
- ```plaintext
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
- ```plaintext
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