shrine 3.0.0.beta2 → 3.0.0.beta3
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 +45 -1
- data/README.md +100 -106
- data/doc/advantages.md +90 -88
- data/doc/attacher.md +322 -152
- data/doc/carrierwave.md +105 -113
- data/doc/changing_derivatives.md +308 -0
- data/doc/changing_location.md +92 -21
- data/doc/changing_storage.md +107 -0
- data/doc/creating_plugins.md +1 -1
- data/doc/design.md +8 -9
- data/doc/direct_s3.md +3 -2
- data/doc/metadata.md +97 -78
- data/doc/multiple_files.md +3 -3
- data/doc/paperclip.md +89 -88
- data/doc/plugins/activerecord.md +3 -12
- data/doc/plugins/backgrounding.md +126 -100
- data/doc/plugins/derivation_endpoint.md +4 -5
- data/doc/plugins/derivatives.md +63 -32
- data/doc/plugins/download_endpoint.md +54 -1
- data/doc/plugins/entity.md +1 -0
- data/doc/plugins/form_assign.md +53 -0
- data/doc/plugins/mirroring.md +37 -16
- data/doc/plugins/multi_cache.md +22 -0
- data/doc/plugins/presign_endpoint.md +1 -1
- data/doc/plugins/remote_url.md +19 -4
- data/doc/plugins/validation.md +83 -0
- data/doc/processing.md +149 -133
- data/doc/refile.md +68 -63
- data/doc/release_notes/3.0.0.md +835 -0
- data/doc/securing_uploads.md +56 -36
- data/doc/storage/s3.md +2 -2
- data/doc/testing.md +104 -120
- data/doc/upgrading_to_3.md +538 -0
- data/doc/validation.md +48 -87
- data/lib/shrine.rb +7 -4
- data/lib/shrine/attacher.rb +16 -6
- data/lib/shrine/plugins/activerecord.rb +33 -14
- data/lib/shrine/plugins/atomic_helpers.rb +1 -1
- data/lib/shrine/plugins/backgrounding.rb +23 -89
- data/lib/shrine/plugins/data_uri.rb +13 -2
- data/lib/shrine/plugins/derivation_endpoint.rb +7 -11
- data/lib/shrine/plugins/derivatives.rb +44 -20
- data/lib/shrine/plugins/download_endpoint.rb +26 -0
- data/lib/shrine/plugins/form_assign.rb +6 -3
- data/lib/shrine/plugins/keep_files.rb +2 -2
- data/lib/shrine/plugins/mirroring.rb +62 -22
- data/lib/shrine/plugins/model.rb +2 -2
- data/lib/shrine/plugins/multi_cache.rb +27 -0
- data/lib/shrine/plugins/remote_url.rb +25 -10
- data/lib/shrine/plugins/remove_invalid.rb +1 -1
- data/lib/shrine/plugins/sequel.rb +39 -20
- data/lib/shrine/plugins/validation.rb +3 -0
- data/lib/shrine/storage/s3.rb +16 -1
- data/lib/shrine/uploaded_file.rb +1 -0
- data/lib/shrine/version.rb +1 -1
- data/shrine.gemspec +1 -1
- metadata +12 -7
- data/doc/migrating_storage.md +0 -76
- data/doc/regenerating_versions.md +0 -143
- data/lib/shrine/plugins/attacher_options.rb +0 -55
@@ -0,0 +1,538 @@
|
|
1
|
+
# Upgrading to Shrine 3.x
|
2
|
+
|
3
|
+
This guide provides instructions for upgrading Shrine in your apps to version
|
4
|
+
3.x. We will cover the following areas:
|
5
|
+
|
6
|
+
* [Attacher](#attacher)
|
7
|
+
* [Backgrounding](#backgrounding)
|
8
|
+
* [Versions](#versions)
|
9
|
+
* [Miscellaneous](#miscellaneous)
|
10
|
+
- [Logging](#logging)
|
11
|
+
- [Backup](#backup)
|
12
|
+
- [Copy](#copy)
|
13
|
+
- [Moving](#moving)
|
14
|
+
- [Memory](#memory)
|
15
|
+
|
16
|
+
## Attacher
|
17
|
+
|
18
|
+
The `Shrine::Attacher` class has been rewritten in Shrine 3.0, though much of
|
19
|
+
the main API remained the same.
|
20
|
+
|
21
|
+
### Model
|
22
|
+
|
23
|
+
The main change is that `Attacher.new` is now used for initializing the
|
24
|
+
attacher without a model:
|
25
|
+
|
26
|
+
```rb
|
27
|
+
attacher = Shrine::Attacher.new
|
28
|
+
# ...
|
29
|
+
|
30
|
+
attacher = Shrine::Attacher.new(photo, :image)
|
31
|
+
# ~> ArgumentError: invalid number of arguments
|
32
|
+
```
|
33
|
+
|
34
|
+
To initialize an attacher with a model, use `Attacher.from_model` provided by
|
35
|
+
the new [`model`][model] plugin (which is automatically loaded by
|
36
|
+
`activerecord` and `sequel` plugins):
|
37
|
+
|
38
|
+
```rb
|
39
|
+
attacher = Shrine::Attacher.from_model(photo, :image)
|
40
|
+
# ...
|
41
|
+
```
|
42
|
+
|
43
|
+
If you're using the `Shrine::Attachment` module with POROs, make sure to load
|
44
|
+
the `model` plugin.
|
45
|
+
|
46
|
+
```rb
|
47
|
+
Shrine.plugin :model
|
48
|
+
```
|
49
|
+
```rb
|
50
|
+
class Photo < Struct.new(:image_data)
|
51
|
+
include Shrine::Attachment(:image)
|
52
|
+
end
|
53
|
+
```
|
54
|
+
|
55
|
+
### Data attribute
|
56
|
+
|
57
|
+
The `Attacher#read` method has been removed. If you want to generate serialized
|
58
|
+
attachment data, use `Attacher#column_data`. Otherwise if you want to generate
|
59
|
+
hash attachment data, use `Attacher#data`.
|
60
|
+
|
61
|
+
```rb
|
62
|
+
attacher.column_data #=> '{"id":"...","storage":"...","metadata":{...}}'
|
63
|
+
attacher.data #=> { "id" => "...", "storage" => "...", "metadata" => { ... } }
|
64
|
+
```
|
65
|
+
|
66
|
+
The `Attacher#data_attribute` has been renamed to `Attacher#attribute`.
|
67
|
+
|
68
|
+
### State
|
69
|
+
|
70
|
+
The attacher now maintains its own state, so if you've previously modified the
|
71
|
+
`#<name>_data` record attribute and expected the changes to be picked up by the
|
72
|
+
attacher, you'll now need to call `Attacher#reload` for that:
|
73
|
+
|
74
|
+
```rb
|
75
|
+
attacher.file #=> nil
|
76
|
+
record.image_data = '{"id":"...","storage":"...","metadata":{...}}'
|
77
|
+
attacher.file #=> nil
|
78
|
+
attacher.reload
|
79
|
+
attacher.file #=> #<Shrine::UploadedFile ...>
|
80
|
+
```
|
81
|
+
|
82
|
+
### Validation
|
83
|
+
|
84
|
+
The validation functionality has been extracted into the `validation` plugin.
|
85
|
+
If you're using the `validation_helpers` plugin, it will automatically load
|
86
|
+
`validation` for you. Otherwise you'll have to load it explicitly:
|
87
|
+
|
88
|
+
```rb
|
89
|
+
Shrine.plugin :validation
|
90
|
+
```
|
91
|
+
```rb
|
92
|
+
class MyUploader < Shrine
|
93
|
+
Attacher.validate do
|
94
|
+
# ...
|
95
|
+
end
|
96
|
+
end
|
97
|
+
```
|
98
|
+
|
99
|
+
### Setting
|
100
|
+
|
101
|
+
The `Attacher#set` method has been renamed to `Attacher#change`, and the
|
102
|
+
private `Attacher#_set` method has been renamed to `Attacher#set` and made
|
103
|
+
public:
|
104
|
+
|
105
|
+
```rb
|
106
|
+
attacher.change(uploaded_file) # sets file, remembers previous file, runs validations
|
107
|
+
attacher.set(uploaded_file) # sets file
|
108
|
+
```
|
109
|
+
|
110
|
+
If you've previously used `Attacher#replace` directly to delete previous file,
|
111
|
+
it has now been renamed to `Attacher#destroy_previous`.
|
112
|
+
|
113
|
+
Also note that `Attacher#attached?` now returns whether a file is attached,
|
114
|
+
while `Attacher#changed?` continues to return whether the attachment has
|
115
|
+
changed.
|
116
|
+
|
117
|
+
### Uploading and deleting
|
118
|
+
|
119
|
+
The `Attacher#store!` and `Attacher#cache!` methods have been removed, you
|
120
|
+
should now use `Attacher#upload` instead:
|
121
|
+
|
122
|
+
```rb
|
123
|
+
attacher.upload(io) # uploads to permanent storage
|
124
|
+
attacher.upload(io, :cache) # uploads to temporary storage
|
125
|
+
attacher.upload(io, :other_store) # uploads to another storage
|
126
|
+
```
|
127
|
+
|
128
|
+
The `Attacher#delete!` method has been removed as well, you should instead just
|
129
|
+
delete the file directly via `UploadedFile#delete`.
|
130
|
+
|
131
|
+
### Promoting
|
132
|
+
|
133
|
+
If you were promoting manually, the `Attacher#promote` method will now only
|
134
|
+
save promoted file in memory, it won't persist the changes.
|
135
|
+
|
136
|
+
```rb
|
137
|
+
attacher.promote
|
138
|
+
# ...
|
139
|
+
record.save # you need to persist the changes
|
140
|
+
```
|
141
|
+
|
142
|
+
If you want the concurrenct-safe promotion with persistence, use the new
|
143
|
+
`Attacher#atomic_promote` method.
|
144
|
+
|
145
|
+
```rb
|
146
|
+
attacher.atomic_promote
|
147
|
+
```
|
148
|
+
|
149
|
+
The `Attacher#swap` method has been removed. If you were using it directly, you
|
150
|
+
can use `Attacher#set` and `Attacher#atomic_persist` instead:
|
151
|
+
|
152
|
+
```rb
|
153
|
+
current_file = attacher.file
|
154
|
+
attacher.set(new_file)
|
155
|
+
attacher.atomic_persist(current_file)
|
156
|
+
```
|
157
|
+
|
158
|
+
## Backgrounding
|
159
|
+
|
160
|
+
The `backgrounding` plugin has been rewritten in Shrine 3.0 and has a new API.
|
161
|
+
|
162
|
+
```rb
|
163
|
+
Shrine.plugin :backgrounding
|
164
|
+
Shrine::Attacher.promote_block { PromoteJob.perform_later(self.class, record, name, file_data) }
|
165
|
+
Shrine::Attacher.destroy_block { DestroyJob.perform_later(self.class, data) }
|
166
|
+
```
|
167
|
+
```rb
|
168
|
+
class PromoteJob < ActiveJob::Base
|
169
|
+
def perform(attacher_class, record, name, file_data)
|
170
|
+
attacher = attacher_class.retrieve(model: record, name: name, file: file_data)
|
171
|
+
attacher.atomic_promote
|
172
|
+
rescue Shrine::AttachmentChanged, ActiveRecord::RecordNotFound
|
173
|
+
# attachment has changed or record has been deleted, nothing to do
|
174
|
+
end
|
175
|
+
end
|
176
|
+
```
|
177
|
+
```rb
|
178
|
+
class DestroyJob < ActiveJob::Base
|
179
|
+
def perform(attacher_class, data)
|
180
|
+
attacher = attacher_class.from_data(data)
|
181
|
+
attacher.destroy
|
182
|
+
end
|
183
|
+
end
|
184
|
+
```
|
185
|
+
|
186
|
+
### Dual support
|
187
|
+
|
188
|
+
When you're making the switch in production, there might still be jobs in the
|
189
|
+
queue that have the old argument format. So, we'll initially want to handle
|
190
|
+
both argument formats, and then switch to the new one once the jobs with old
|
191
|
+
format have been drained.
|
192
|
+
|
193
|
+
```rb
|
194
|
+
class PromoteJob < ActiveJob::Base
|
195
|
+
def perform(*args)
|
196
|
+
if args.one?
|
197
|
+
file_data, (record_class, record_id), name, shrine_class =
|
198
|
+
args.first.values_at("attachment", "record", "name", "shrine_class")
|
199
|
+
|
200
|
+
record = Object.const_get(record_class).find(record_id)
|
201
|
+
attacher_class = Object.const_get(shrine_class)::Attacher
|
202
|
+
else
|
203
|
+
attacher_class, record, name, file_data = args
|
204
|
+
end
|
205
|
+
|
206
|
+
attacher = attacher_class.retrieve(model: record, name: name, file: file_data)
|
207
|
+
attacher.atomic_promote
|
208
|
+
rescue Shrine::AttachmentChanged, ActiveRecord::RecordNotFound
|
209
|
+
# attachment has changed or record has been deleted, nothing to do
|
210
|
+
end
|
211
|
+
and
|
212
|
+
```
|
213
|
+
```rb
|
214
|
+
class DestroyJob < ActiveJob::Base
|
215
|
+
def perform(*args)
|
216
|
+
if args.one?
|
217
|
+
data, shrine_class = args.first.values_at("attachment", "shrine_class")
|
218
|
+
|
219
|
+
data = JSON.parse(data)
|
220
|
+
attacher_class = Object.const_get(shrine_class)::Attacher
|
221
|
+
else
|
222
|
+
attacher_class, data = args
|
223
|
+
end
|
224
|
+
|
225
|
+
attacher = attacher_class.from_data(data)
|
226
|
+
attacher.destroy
|
227
|
+
end
|
228
|
+
and
|
229
|
+
```
|
230
|
+
|
231
|
+
### Attacher backgrounding
|
232
|
+
|
233
|
+
In Shrine 2.x, `Attacher#_promote` and `Attacher#_delete` methods could be used
|
234
|
+
to spawn promote and delete jobs. This is now done by `Attacher#promote_cached`
|
235
|
+
and `Attacher#destroy_attached`:
|
236
|
+
|
237
|
+
```rb
|
238
|
+
attacher.promote_cached # will spawn background job if registered
|
239
|
+
attacher.destroy_attached # will spawn background job if registered
|
240
|
+
```
|
241
|
+
|
242
|
+
If you want to explicitly call backgrounding blocks, you can use
|
243
|
+
`Attacher#promote_background` and `Attacher#destroy_background`:
|
244
|
+
|
245
|
+
```rb
|
246
|
+
attacher.promote_background # calls promote block
|
247
|
+
attacher.destroy_background # calls destroy block
|
248
|
+
```
|
249
|
+
|
250
|
+
## Versions
|
251
|
+
|
252
|
+
The `versions`, `processing`, `recache`, and `delete_raw` plugins have been
|
253
|
+
deprecated in favour of the new [`derivatives`][derivatives] plugin. Let's
|
254
|
+
assume you have the following `versions` code:
|
255
|
+
|
256
|
+
```rb
|
257
|
+
class ImageUploader < Shrine
|
258
|
+
plugin :processing
|
259
|
+
plugin :versions
|
260
|
+
plugin :delete_raw
|
261
|
+
|
262
|
+
process(:store) do |file, context|
|
263
|
+
versions = { original: file }
|
264
|
+
|
265
|
+
file.download do |original|
|
266
|
+
magick = ImageProcessing::MiniMagick.source(original)
|
267
|
+
|
268
|
+
versions[:large] = magick.resize_to_limit!(800, 800)
|
269
|
+
versions[:medium] = magick.resize_to_limit!(500, 500)
|
270
|
+
versions[:small] = magick.resize_to_limit!(300, 300)
|
271
|
+
end
|
272
|
+
|
273
|
+
versions
|
274
|
+
end
|
275
|
+
end
|
276
|
+
```
|
277
|
+
```rb
|
278
|
+
photo = Photo.new(photo_params)
|
279
|
+
|
280
|
+
if photo.valid?
|
281
|
+
photo.save # automatically calls processing block
|
282
|
+
# ...
|
283
|
+
else
|
284
|
+
# ...
|
285
|
+
end
|
286
|
+
```
|
287
|
+
|
288
|
+
With `derivatives` it becomes this:
|
289
|
+
|
290
|
+
```rb
|
291
|
+
Shrine.plugin :derivatives, versions_compatibility: true # handle versions column format
|
292
|
+
```
|
293
|
+
```rb
|
294
|
+
class ImageUploader < Shrine
|
295
|
+
Attacher.derivatives_processor do |original|
|
296
|
+
magick = ImageProcessing::MiniMagick.source(original)
|
297
|
+
|
298
|
+
{
|
299
|
+
large: magick.resize_to_limit!(800, 800),
|
300
|
+
medium: magick.resize_to_limit!(500, 500),
|
301
|
+
small: magick.resize_to_limit!(300, 300),
|
302
|
+
}
|
303
|
+
end
|
304
|
+
end
|
305
|
+
```
|
306
|
+
```rb
|
307
|
+
photo = Photo.new(photo_params)
|
308
|
+
|
309
|
+
if photo.valid?
|
310
|
+
photo.image_derivatives! if photo.image_changed? # create derivatives
|
311
|
+
photo.save # automatically calls processing block
|
312
|
+
# ...
|
313
|
+
else
|
314
|
+
# ...
|
315
|
+
end
|
316
|
+
```
|
317
|
+
|
318
|
+
The derivative URLs are accessed in the same way as versions:
|
319
|
+
|
320
|
+
```rb
|
321
|
+
photo.image_url(:small)
|
322
|
+
```
|
323
|
+
|
324
|
+
But the derivatives themselves are accessed differently:
|
325
|
+
|
326
|
+
```rb
|
327
|
+
# versions
|
328
|
+
photo.image #=>
|
329
|
+
# {
|
330
|
+
# original: #<Shrine::UploadedFile ...>,
|
331
|
+
# large: #<Shrine::UploadedFile ...>,
|
332
|
+
# medium: #<Shrine::UploadedFile ...>,
|
333
|
+
# small: #<Shrine::UploadedFile ...>,
|
334
|
+
# }
|
335
|
+
photo.image[:medium] #=> #<Shrine::UploadedFile ...>
|
336
|
+
```
|
337
|
+
```rb
|
338
|
+
# derivatives
|
339
|
+
photo.image_derivatives #=>
|
340
|
+
# {
|
341
|
+
# large: #<Shrine::UploadedFile ...>,
|
342
|
+
# medium: #<Shrine::UploadedFile ...>,
|
343
|
+
# small: #<Shrine::UploadedFile ...>,
|
344
|
+
# }
|
345
|
+
photo.image(:medium) #=> #<Shrine::UploadedFile ...>
|
346
|
+
```
|
347
|
+
|
348
|
+
### Migrating versions
|
349
|
+
|
350
|
+
The `versions` and `derivatives` plugins save processed file data to the
|
351
|
+
database column in different formats:
|
352
|
+
|
353
|
+
```rb
|
354
|
+
# versions
|
355
|
+
{
|
356
|
+
"original": { "id": "...", "storage": "...", "metadata": { ... } },
|
357
|
+
"large": { "id": "...", "storage": "...", "metadata": { ... } },
|
358
|
+
"medium": { "id": "...", "storage": "...", "metadata": { ... } },
|
359
|
+
"small": { "id": "...", "storage": "...", "metadata": { ... } }
|
360
|
+
}
|
361
|
+
```
|
362
|
+
```rb
|
363
|
+
# derivatives
|
364
|
+
{
|
365
|
+
"id": "...",
|
366
|
+
"storage": "...",
|
367
|
+
"metadata": { ... },
|
368
|
+
"derivatives": {
|
369
|
+
"large": { "id": "...", "storage": "...", "metadata": { ... } },
|
370
|
+
"medium": { "id": "...", "storage": "...", "metadata": { ... } },
|
371
|
+
"small": { "id": "...", "storage": "...", "metadata": { ... } }
|
372
|
+
}
|
373
|
+
}
|
374
|
+
```
|
375
|
+
|
376
|
+
The `:versions_compatibility` flag to the `derivatives` plugin enables it to
|
377
|
+
read the `versions` format, which aids in transition. Once the `derivatives`
|
378
|
+
plugin has been deployed to production, you can switch existing records to the
|
379
|
+
new column format:
|
380
|
+
|
381
|
+
```rb
|
382
|
+
Photo.find_each do |photo|
|
383
|
+
photo.image_attacher.write
|
384
|
+
photo.image_attacher.atomic_persist
|
385
|
+
end
|
386
|
+
```
|
387
|
+
|
388
|
+
Afterwards you should be able to remove the `:versions_compatibility` flag.
|
389
|
+
|
390
|
+
### Backgrounding derivatives
|
391
|
+
|
392
|
+
If you're using the `backgrounding` plugin, you can trigger derivatives
|
393
|
+
creation in the `PromoteJob` instead of the controller:
|
394
|
+
|
395
|
+
```rb
|
396
|
+
class PromoteJob < ActiveJob::Base
|
397
|
+
def perform(attacher_class, record, name, file_data)
|
398
|
+
attacher = attacher_class.retrieve(model: record, name: name, file: file_data)
|
399
|
+
attacher.create_derivatives # call derivatives processor
|
400
|
+
attacher.atomic_promote
|
401
|
+
rescue Shrine::AttachmentChanged, ActiveRecord::RecordNotFound
|
402
|
+
# attachment has changed or record has beeen deleted, nothing to do
|
403
|
+
end
|
404
|
+
end
|
405
|
+
```
|
406
|
+
|
407
|
+
#### Recache
|
408
|
+
|
409
|
+
If you were using the `recache` plugin, you can replicate the behaviour by
|
410
|
+
creating another derivatives processor that you will trigger in the controller:
|
411
|
+
|
412
|
+
```rb
|
413
|
+
class ImageUploader < Shrine
|
414
|
+
Attacher.derivatives_processor do |original|
|
415
|
+
# this will be triggered in the background job
|
416
|
+
end
|
417
|
+
|
418
|
+
Attacher.derivatives_processor :foreground do |original|
|
419
|
+
# this will be triggered in the controller
|
420
|
+
end
|
421
|
+
end
|
422
|
+
```
|
423
|
+
```rb
|
424
|
+
photo = Photo.new(photo_params)
|
425
|
+
|
426
|
+
if photo.valid?
|
427
|
+
photo.image_derivatives!(:foreground) if photo.image_changed?
|
428
|
+
photo.save
|
429
|
+
# ...
|
430
|
+
else
|
431
|
+
# ...
|
432
|
+
end
|
433
|
+
```
|
434
|
+
|
435
|
+
#### Parallelize
|
436
|
+
|
437
|
+
The `parallelize` plugin has been removed. The `derivatives` plugin is
|
438
|
+
thread-safe, so you can parallelize uploading processed files manually:
|
439
|
+
|
440
|
+
```rb
|
441
|
+
# Gemfile
|
442
|
+
gem "concurrent-ruby"
|
443
|
+
```
|
444
|
+
```rb
|
445
|
+
require "concurrent"
|
446
|
+
|
447
|
+
derivatives = attacher.process_derivatives
|
448
|
+
|
449
|
+
tasks = derivatives.map do |name, file|
|
450
|
+
Concurrent::Promises.future(name, file) do |name, file|
|
451
|
+
attacher.add_derivative(name, file)
|
452
|
+
end
|
453
|
+
end
|
454
|
+
|
455
|
+
Concurrent::Promises.zip(*tasks).wait!
|
456
|
+
```
|
457
|
+
|
458
|
+
#### Default URL
|
459
|
+
|
460
|
+
The `derivatives` plugin integrates with the `default_url` plugin:
|
461
|
+
|
462
|
+
```rb
|
463
|
+
Attacher.default_url do |derivative: nil, **|
|
464
|
+
"https://my-app.com/fallbacks/#{derivative}.jpg" if derivative
|
465
|
+
end
|
466
|
+
```
|
467
|
+
|
468
|
+
However, it doesn't implement any other URL fallbacks that the `versions`
|
469
|
+
plugin has for missing derivatives.
|
470
|
+
|
471
|
+
## Miscellaneous
|
472
|
+
|
473
|
+
### Logging
|
474
|
+
|
475
|
+
The `logging` plugin has been removed in favour of the
|
476
|
+
[`instrumentation`][instrumentation] plugin. You can replace
|
477
|
+
|
478
|
+
```rb
|
479
|
+
Shrine.plugin :logging, logger: Rails.logger
|
480
|
+
```
|
481
|
+
|
482
|
+
with
|
483
|
+
|
484
|
+
```rb
|
485
|
+
Shrine.logger = Rails.logger
|
486
|
+
|
487
|
+
Shrine.plugin :instrumentation
|
488
|
+
```
|
489
|
+
|
490
|
+
### Backup
|
491
|
+
|
492
|
+
The `backup` plugin has been removed in favour of the new
|
493
|
+
[`mirroring`][mirroring] plugin. You can replace
|
494
|
+
|
495
|
+
```rb
|
496
|
+
Shrine.plugin :backup, storage: :backup_store
|
497
|
+
```
|
498
|
+
|
499
|
+
with
|
500
|
+
|
501
|
+
```rb
|
502
|
+
Shrine.plugin :mirroring, mirror: { store: :backup_store }
|
503
|
+
```
|
504
|
+
|
505
|
+
### Copy
|
506
|
+
|
507
|
+
The `copy` plugin has been removed. You can replace
|
508
|
+
|
509
|
+
```rb
|
510
|
+
Shrine.plugin :copy
|
511
|
+
```
|
512
|
+
```rb
|
513
|
+
attacher.copy(other_attacher)
|
514
|
+
```
|
515
|
+
|
516
|
+
with
|
517
|
+
|
518
|
+
```rb
|
519
|
+
attacher.attach other_attacher.file
|
520
|
+
attacher.add_derivatives other_attacher.derivatives # if using derivatives
|
521
|
+
```
|
522
|
+
|
523
|
+
### Moving
|
524
|
+
|
525
|
+
The `moving` plugin has been removed in favour of the `:move` option for
|
526
|
+
`FileSystem#upload`. You can set up moving in basic places with the
|
527
|
+
`upload_options` plugin:
|
528
|
+
|
529
|
+
```rb
|
530
|
+
Shrine.plugin :upload_options,
|
531
|
+
cache: -> (io, action: nil, **) { { move: true } if action == :cache },
|
532
|
+
store: -> (io, action: nil, **) { { move: true } if action == :store }
|
533
|
+
```
|
534
|
+
|
535
|
+
[model]: /doc/plugins/model.md#readme
|
536
|
+
[derivatives]: /doc/plugins/derivatives.md#readme
|
537
|
+
[instrumentation]: /doc/plugins/instrumentation.md#readme
|
538
|
+
[mirroring]: /doc/plugins/mirroring.md#readme
|