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
@@ -32,42 +32,26 @@ class Shrine
|
|
32
32
|
name = @name
|
33
33
|
|
34
34
|
if shrine_class.opts[:sequel][:validations]
|
35
|
-
# add validation plugin integration
|
36
35
|
define_method :validate do
|
37
36
|
super()
|
38
|
-
|
39
|
-
|
40
|
-
send(:"#{name}_attacher").errors.each do |message|
|
41
|
-
errors.add(name, *message)
|
42
|
-
end
|
37
|
+
send(:"#{name}_attacher").send(:sequel_validate)
|
43
38
|
end
|
44
39
|
end
|
45
40
|
|
46
41
|
if shrine_class.opts[:sequel][:hooks]
|
47
42
|
define_method :before_save do
|
48
43
|
super()
|
49
|
-
|
50
|
-
send(:"#{name}_attacher").save
|
51
|
-
end
|
44
|
+
send(:"#{name}_attacher").send(:sequel_before_save)
|
52
45
|
end
|
53
46
|
|
54
47
|
define_method :after_save do
|
55
48
|
super()
|
56
|
-
|
57
|
-
db.after_commit do
|
58
|
-
send(:"#{name}_attacher").finalize
|
59
|
-
send(:"#{name}_attacher").persist
|
60
|
-
end
|
61
|
-
end
|
49
|
+
send(:"#{name}_attacher").send(:sequel_after_save)
|
62
50
|
end
|
63
51
|
|
64
52
|
define_method :after_destroy do
|
65
53
|
super()
|
66
|
-
|
67
|
-
db.after_commit do
|
68
|
-
send(:"#{name}_attacher").destroy_attached
|
69
|
-
end
|
70
|
-
end
|
54
|
+
send(:"#{name}_attacher").send(:sequel_after_destroy)
|
71
55
|
end
|
72
56
|
end
|
73
57
|
|
@@ -90,6 +74,41 @@ class Shrine
|
|
90
74
|
module AttacherMethods
|
91
75
|
private
|
92
76
|
|
77
|
+
# Adds file validation errors to the model. Called on model validation.
|
78
|
+
def sequel_validate
|
79
|
+
return unless respond_to?(:errors)
|
80
|
+
|
81
|
+
errors.each do |message|
|
82
|
+
record.errors.add(name, *message)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# Calls Attacher#save. Called before model save.
|
87
|
+
def sequel_before_save
|
88
|
+
return unless changed?
|
89
|
+
|
90
|
+
save
|
91
|
+
end
|
92
|
+
|
93
|
+
# Finalizes attachment and persists changes. Called after model save.
|
94
|
+
def sequel_after_save
|
95
|
+
return unless changed?
|
96
|
+
|
97
|
+
record.db.after_commit do
|
98
|
+
finalize
|
99
|
+
persist
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# Deletes attached files. Called after model destroy.
|
104
|
+
def sequel_after_destroy
|
105
|
+
return unless attached?
|
106
|
+
|
107
|
+
record.db.after_commit do
|
108
|
+
destroy_attached
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
93
112
|
# Saves changes to the model instance, skipping validations. Used by
|
94
113
|
# the _persistence plugin.
|
95
114
|
def sequel_persist
|
@@ -2,6 +2,9 @@
|
|
2
2
|
|
3
3
|
class Shrine
|
4
4
|
module Plugins
|
5
|
+
# Documentation lives in [doc/plugins/validation.md] on GitHub.
|
6
|
+
#
|
7
|
+
# [doc/plugins/validation.md]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/validation.md
|
5
8
|
module Validation
|
6
9
|
module AttacherClassMethods
|
7
10
|
# Block that is executed in context of Shrine::Attacher during
|
data/lib/shrine/storage/s3.rb
CHANGED
@@ -15,6 +15,9 @@ class Shrine
|
|
15
15
|
class S3
|
16
16
|
attr_reader :client, :bucket, :prefix, :upload_options, :signer, :public
|
17
17
|
|
18
|
+
MAX_MULTIPART_PARTS = 10_000
|
19
|
+
MIN_PART_SIZE = 5*1024*1024
|
20
|
+
|
18
21
|
MULTIPART_THRESHOLD = { upload: 15*1024*1024, copy: 100*1024*1024 }
|
19
22
|
|
20
23
|
# Initializes a storage for uploading to S3. All options are forwarded to
|
@@ -242,12 +245,24 @@ class Shrine
|
|
242
245
|
if io.respond_to?(:size) && io.size && io.size <= @multipart_threshold[:upload]
|
243
246
|
object(id).put(body: io, **options)
|
244
247
|
else # multipart upload
|
245
|
-
object(id).upload_stream(**options) do |write_stream|
|
248
|
+
object(id).upload_stream(part_size: part_size(io), **options) do |write_stream|
|
246
249
|
IO.copy_stream(io, write_stream)
|
247
250
|
end
|
248
251
|
end
|
249
252
|
end
|
250
253
|
|
254
|
+
# Determins the part size that should be used when uploading the given IO
|
255
|
+
# object via multipart upload.
|
256
|
+
def part_size(io)
|
257
|
+
return unless io.respond_to?(:size) && io.size
|
258
|
+
|
259
|
+
if io.size <= MIN_PART_SIZE * MAX_MULTIPART_PARTS # <= 50 GB
|
260
|
+
MIN_PART_SIZE
|
261
|
+
else # > 50 GB
|
262
|
+
(io.size.to_f / MAX_MULTIPART_PARTS).ceil
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
251
266
|
# Aws::S3::Object#get doesn't allow us to get the content length of the
|
252
267
|
# object before the content is downloaded, so we hack our way around it.
|
253
268
|
def get_object(object, params)
|
data/lib/shrine/uploaded_file.rb
CHANGED
data/lib/shrine/version.rb
CHANGED
data/shrine.gemspec
CHANGED
@@ -26,7 +26,7 @@ direct uploads for fully asynchronous user experience.
|
|
26
26
|
"bug_tracker_uri" => "https://github.com/shrinerb/shrine/issues",
|
27
27
|
"changelog_uri" => "https://github.com/shrinerb/shrine/blob/master/CHANGELOG.md",
|
28
28
|
"documentation_uri" => "https://shrinerb.com",
|
29
|
-
"mailing_list_uri" => "https://
|
29
|
+
"mailing_list_uri" => "https://discourse.shrinerb.com",
|
30
30
|
"source_code_uri" => "https://github.com/shrinerb/shrine",
|
31
31
|
}
|
32
32
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shrine
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.0.0.
|
4
|
+
version: 3.0.0.beta3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Janko Marohnić
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-09-
|
11
|
+
date: 2019-09-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: down
|
@@ -367,14 +367,15 @@ files:
|
|
367
367
|
- doc/advantages.md
|
368
368
|
- doc/attacher.md
|
369
369
|
- doc/carrierwave.md
|
370
|
+
- doc/changing_derivatives.md
|
370
371
|
- doc/changing_location.md
|
372
|
+
- doc/changing_storage.md
|
371
373
|
- doc/creating_persistence_plugins.md
|
372
374
|
- doc/creating_plugins.md
|
373
375
|
- doc/creating_storages.md
|
374
376
|
- doc/design.md
|
375
377
|
- doc/direct_s3.md
|
376
378
|
- doc/metadata.md
|
377
|
-
- doc/migrating_storage.md
|
378
379
|
- doc/multiple_files.md
|
379
380
|
- doc/paperclip.md
|
380
381
|
- doc/plugins/activerecord.md
|
@@ -393,6 +394,7 @@ files:
|
|
393
394
|
- doc/plugins/download_endpoint.md
|
394
395
|
- doc/plugins/dynamic_storage.md
|
395
396
|
- doc/plugins/entity.md
|
397
|
+
- doc/plugins/form_assign.md
|
396
398
|
- doc/plugins/included.md
|
397
399
|
- doc/plugins/infer_extension.md
|
398
400
|
- doc/plugins/instrumentation.md
|
@@ -401,6 +403,7 @@ files:
|
|
401
403
|
- doc/plugins/mirroring.md
|
402
404
|
- doc/plugins/model.md
|
403
405
|
- doc/plugins/module_include.md
|
406
|
+
- doc/plugins/multi_cache.md
|
404
407
|
- doc/plugins/persistence.md
|
405
408
|
- doc/plugins/presign_endpoint.md
|
406
409
|
- doc/plugins/pretty_location.md
|
@@ -420,11 +423,11 @@ files:
|
|
420
423
|
- doc/plugins/upload_endpoint.md
|
421
424
|
- doc/plugins/upload_options.md
|
422
425
|
- doc/plugins/url_options.md
|
426
|
+
- doc/plugins/validation.md
|
423
427
|
- doc/plugins/validation_helpers.md
|
424
428
|
- doc/plugins/versions.md
|
425
429
|
- doc/processing.md
|
426
430
|
- doc/refile.md
|
427
|
-
- doc/regenerating_versions.md
|
428
431
|
- doc/release_notes/1.0.0.md
|
429
432
|
- doc/release_notes/1.1.0.md
|
430
433
|
- doc/release_notes/1.2.0.md
|
@@ -458,11 +461,13 @@ files:
|
|
458
461
|
- doc/release_notes/2.7.0.md
|
459
462
|
- doc/release_notes/2.8.0.md
|
460
463
|
- doc/release_notes/2.9.0.md
|
464
|
+
- doc/release_notes/3.0.0.md
|
461
465
|
- doc/retrieving_uploads.md
|
462
466
|
- doc/securing_uploads.md
|
463
467
|
- doc/storage/file_system.md
|
464
468
|
- doc/storage/s3.md
|
465
469
|
- doc/testing.md
|
470
|
+
- doc/upgrading_to_3.md
|
466
471
|
- doc/validation.md
|
467
472
|
- lib/shrine.rb
|
468
473
|
- lib/shrine/attacher.rb
|
@@ -473,7 +478,6 @@ files:
|
|
473
478
|
- lib/shrine/plugins/activerecord.rb
|
474
479
|
- lib/shrine/plugins/add_metadata.rb
|
475
480
|
- lib/shrine/plugins/atomic_helpers.rb
|
476
|
-
- lib/shrine/plugins/attacher_options.rb
|
477
481
|
- lib/shrine/plugins/backgrounding.rb
|
478
482
|
- lib/shrine/plugins/cached_attachment_data.rb
|
479
483
|
- lib/shrine/plugins/column.rb
|
@@ -497,6 +501,7 @@ files:
|
|
497
501
|
- lib/shrine/plugins/mirroring.rb
|
498
502
|
- lib/shrine/plugins/model.rb
|
499
503
|
- lib/shrine/plugins/module_include.rb
|
504
|
+
- lib/shrine/plugins/multi_cache.rb
|
500
505
|
- lib/shrine/plugins/presign_endpoint.rb
|
501
506
|
- lib/shrine/plugins/pretty_location.rb
|
502
507
|
- lib/shrine/plugins/processing.rb
|
@@ -532,7 +537,7 @@ metadata:
|
|
532
537
|
bug_tracker_uri: https://github.com/shrinerb/shrine/issues
|
533
538
|
changelog_uri: https://github.com/shrinerb/shrine/blob/master/CHANGELOG.md
|
534
539
|
documentation_uri: https://shrinerb.com
|
535
|
-
mailing_list_uri: https://
|
540
|
+
mailing_list_uri: https://discourse.shrinerb.com
|
536
541
|
source_code_uri: https://github.com/shrinerb/shrine
|
537
542
|
post_install_message:
|
538
543
|
rdoc_options: []
|
@@ -549,7 +554,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
549
554
|
- !ruby/object:Gem::Version
|
550
555
|
version: 1.3.1
|
551
556
|
requirements: []
|
552
|
-
rubygems_version: 3.0.
|
557
|
+
rubygems_version: 3.0.3
|
553
558
|
signing_key:
|
554
559
|
specification_version: 4
|
555
560
|
summary: Toolkit for file attachments in Ruby applications
|
data/doc/migrating_storage.md
DELETED
@@ -1,76 +0,0 @@
|
|
1
|
-
# Migrating to Different Storage
|
2
|
-
|
3
|
-
While your application is live in production and performing uploads, it may
|
4
|
-
happen that you decide you want to change your storage (the `:store`). Shrine
|
5
|
-
by design allows you to do that easily, with zero downtime, by deploying the
|
6
|
-
change in 2 phases.
|
7
|
-
|
8
|
-
## Phase 1: Changing the storage
|
9
|
-
|
10
|
-
The first stage, add the desired storage to your registry, and make it your
|
11
|
-
current store (let's say that you're migrating from FileSystem to S3):
|
12
|
-
|
13
|
-
```rb
|
14
|
-
Shrine.storages = {
|
15
|
-
cache: Shrine::Storage::FileSystem.new("public", prefix: "uploads/cache"),
|
16
|
-
store: Shrine::Storage::FileSystem.new("public", prefix: "uploads"),
|
17
|
-
new_store: Shrine::Storage::S3.new(**s3_options),
|
18
|
-
}
|
19
|
-
|
20
|
-
Shrine.plugin :default_storage, store: :new_store
|
21
|
-
```
|
22
|
-
|
23
|
-
This will make already uploaded files stay uploaded on `:store`, and all new
|
24
|
-
files will be uploaded to `:new_store`.
|
25
|
-
|
26
|
-
## Phase 2: Copying existing files
|
27
|
-
|
28
|
-
After you've deployed the previous change, it's time to copy all the existing
|
29
|
-
files to the new storage, and update the records. This is how you can do it
|
30
|
-
if you're using Sequel:
|
31
|
-
|
32
|
-
```rb
|
33
|
-
User.paged_each do |user|
|
34
|
-
if (attacher = user.avatar_attacher).stored?
|
35
|
-
uploaded_file = attacher.store!(user.avatar)
|
36
|
-
attacher.swap(uploaded_file)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
# Repeat for all other attachments and models
|
41
|
-
```
|
42
|
-
|
43
|
-
Now your uploaded files are successfully copied to the new storage, so you
|
44
|
-
should be able to safely delete the old one.
|
45
|
-
|
46
|
-
## Phase 3 and 4: Renaming new storage (optional)
|
47
|
-
|
48
|
-
The uploads will now be happening on the right storage, but if you would rather
|
49
|
-
rename `:new_store` back to `:store`, you can do two more phases. **First** you
|
50
|
-
need to deploy aliasing `:new_store` to `:store` (and make the default storage
|
51
|
-
be `:store` again):
|
52
|
-
|
53
|
-
```rb
|
54
|
-
Shrine.storages = {
|
55
|
-
cache: Shrine::Storage::FileSystem.new("public", prefix: "uploads/cache"),
|
56
|
-
store: Shrine::Storage::S3.new(**s3_options),
|
57
|
-
}
|
58
|
-
|
59
|
-
Shrine.storages[:new_store] = Shrine.storages[:store]
|
60
|
-
```
|
61
|
-
|
62
|
-
**Second**, you should rename the storage names on existing records. With
|
63
|
-
Sequel it would be something like:
|
64
|
-
|
65
|
-
```rb
|
66
|
-
User.paged_each do |user|
|
67
|
-
if user.avatar_attacher.stored?
|
68
|
-
user.update(avatar_data: user.avatar_data.gsub('"new_store"', '"store"'))
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
# Repeat for all other attachments and models
|
73
|
-
```
|
74
|
-
|
75
|
-
Now everything should be in order and you should be able to remove the
|
76
|
-
`:new_store` alias.
|
@@ -1,143 +0,0 @@
|
|
1
|
-
# Reprocessing Versions
|
2
|
-
|
3
|
-
While your app is serving uploads in production, you may realize that you want
|
4
|
-
to change how your attachment's versions are generated. This means that, in
|
5
|
-
addition to changing your processing code, you also need to reprocess the
|
6
|
-
existing attachments. This guide is aimed to help doing this migration with
|
7
|
-
zero downtime and no unused files left in the main storage.
|
8
|
-
|
9
|
-
## Adding versions
|
10
|
-
|
11
|
-
Most common scenario is when initially you're not doing any processing, but
|
12
|
-
later decide that you want to generate versions. First you need to update your
|
13
|
-
code to generate versions, and you also need to change your views to use those
|
14
|
-
versions:
|
15
|
-
|
16
|
-
```rb
|
17
|
-
class ImageUploader < Shrine
|
18
|
-
# ...
|
19
|
-
|
20
|
-
process(:store) do |io, context|
|
21
|
-
thumbnail = process_thumbnail(io.download)
|
22
|
-
{original: io, thumbnail: thumbnail}
|
23
|
-
end
|
24
|
-
end
|
25
|
-
```
|
26
|
-
```rb
|
27
|
-
# In your views add the version name to all <attachment>_url calls.
|
28
|
-
user.avatar_url(:thumb)
|
29
|
-
```
|
30
|
-
|
31
|
-
Note that you should deploy both of these changes at once, because the
|
32
|
-
`<attachment>_url` method will fail if there are versions generated but no
|
33
|
-
version name was passed in. If a version name was passed in but versions aren't
|
34
|
-
generated yet (which will be the case here), it will just return the
|
35
|
-
unprocessed file URL.
|
36
|
-
|
37
|
-
Afterwards you should run a script which reprocesses the versions for existing
|
38
|
-
files:
|
39
|
-
|
40
|
-
```rb
|
41
|
-
User.paged_each do |user|
|
42
|
-
attacher, attachment = user.avatar_attacher, user.avatar
|
43
|
-
if attacher.stored? && !attachment.is_a?(Hash)
|
44
|
-
file = some_processing(attachment.download)
|
45
|
-
thumb = attacher.store!(file, version: :thumb)
|
46
|
-
attacher.swap({original: attachment, thumb: thumb})
|
47
|
-
end
|
48
|
-
end
|
49
|
-
```
|
50
|
-
|
51
|
-
## Reprocessing a single version
|
52
|
-
|
53
|
-
The simplest scenario is where you need to regenerate an existing version.
|
54
|
-
First you need to change and deploy your updated processing code, and
|
55
|
-
afterwards you can run a script like this on your production database:
|
56
|
-
|
57
|
-
```rb
|
58
|
-
User.paged_each do |user|
|
59
|
-
attacher, attachment = user.avatar_attacher, user.avatar
|
60
|
-
if attacher.stored?
|
61
|
-
file = some_processing(attachment[:original].download)
|
62
|
-
thumb = attachment[:thumb].replace(thumb)
|
63
|
-
attacher.swap(attachment.merge(thumb: thumb))
|
64
|
-
end
|
65
|
-
end
|
66
|
-
```
|
67
|
-
|
68
|
-
### Adding a new version
|
69
|
-
|
70
|
-
When adding a new version to a production app, first add it to the list and
|
71
|
-
update your processing code to generate it, and deploy it:
|
72
|
-
|
73
|
-
```rb
|
74
|
-
class ImageUploader < Shrine
|
75
|
-
# ...
|
76
|
-
|
77
|
-
process(:store) do |io, context|
|
78
|
-
# ...
|
79
|
-
new = some_processing(io.download, *args)
|
80
|
-
{small: small, medium: medium, new: new} # we generate the ":new" version
|
81
|
-
end
|
82
|
-
end
|
83
|
-
```
|
84
|
-
|
85
|
-
After you've deployed this change, you should run a script that will generate
|
86
|
-
the new version for all existing records:
|
87
|
-
|
88
|
-
```rb
|
89
|
-
User.paged_each do |user|
|
90
|
-
attacher, attachment = user.avatar_attacher, user.avatar
|
91
|
-
if attacher.stored? && !attachment[:new]
|
92
|
-
file = some_processing(attachment[:original].download, *args)
|
93
|
-
new = attacher.store!(file, version: :new)
|
94
|
-
attacher.swap(attachment.merge(new: new))
|
95
|
-
end
|
96
|
-
end
|
97
|
-
```
|
98
|
-
|
99
|
-
After you've run this script on your production database, all records should
|
100
|
-
have the new version, and now you should be able to safely update your app to
|
101
|
-
use it.
|
102
|
-
|
103
|
-
### Removing a version
|
104
|
-
|
105
|
-
Before removing a version, you first need to update your processing to not
|
106
|
-
generate it (but keep the version name in the list), as well as update your app
|
107
|
-
not to use the new version, and deploy that code. After you've done that, you
|
108
|
-
can run a script which removes that version:
|
109
|
-
|
110
|
-
```rb
|
111
|
-
old_versions = []
|
112
|
-
|
113
|
-
User.paged_each do |user|
|
114
|
-
attacher, attachment = user.avatar_attacher, user.avatar
|
115
|
-
if attacher.stored? && attachment[:old_version]
|
116
|
-
old_versions << attachment.delete(:old_version)
|
117
|
-
attacher.swap(attachment)
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
if old_versions.any?
|
122
|
-
uploader = old_versions.first.uploader
|
123
|
-
uploader.delete(old_versions)
|
124
|
-
end
|
125
|
-
```
|
126
|
-
|
127
|
-
After the script has finished, you should be able to safely remove the version
|
128
|
-
name from the list.
|
129
|
-
|
130
|
-
## Reprocessing all versions
|
131
|
-
|
132
|
-
If you made a lot of changes to versions, it might make sense to simply
|
133
|
-
regenerate all versions. After you've deployed the change in processing, you
|
134
|
-
can run a script which updates existing records:
|
135
|
-
|
136
|
-
```rb
|
137
|
-
User.paged_each do |user|
|
138
|
-
if user.avatar_attacher.stored?
|
139
|
-
# assuming your largest version is named ":original"
|
140
|
-
user.update(avatar: user.avatar[:original])
|
141
|
-
end
|
142
|
-
end
|
143
|
-
```
|