shrine 2.19.3 → 3.6.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 +523 -41
- data/LICENSE.txt +1 -1
- data/README.md +83 -979
- data/doc/advantages.md +231 -204
- data/doc/attacher.md +304 -153
- data/doc/carrierwave.md +297 -226
- data/doc/changing_derivatives.md +308 -0
- data/doc/changing_location.md +103 -21
- data/doc/changing_storage.md +110 -0
- data/doc/creating_persistence_plugins.md +132 -0
- data/doc/creating_plugins.md +43 -23
- data/doc/creating_storages.md +19 -5
- data/doc/design.md +147 -97
- data/doc/direct_s3.md +38 -28
- data/doc/external/articles.md +63 -0
- data/doc/external/extensions.md +53 -0
- data/doc/external/misc.md +32 -0
- data/doc/getting_started.md +1156 -0
- data/doc/metadata.md +190 -109
- data/doc/multiple_files.md +93 -30
- data/doc/paperclip.md +384 -262
- data/doc/plugins/activerecord.md +177 -46
- data/doc/plugins/add_metadata.md +139 -38
- data/doc/plugins/atomic_helpers.md +217 -0
- data/doc/plugins/backgrounding.md +156 -98
- data/doc/plugins/cached_attachment_data.md +7 -5
- data/doc/plugins/column.md +121 -0
- data/doc/plugins/data_uri.md +23 -22
- data/doc/plugins/default_storage.md +36 -10
- data/doc/plugins/default_url.md +30 -13
- data/doc/plugins/delete_raw.md +4 -2
- data/doc/plugins/derivation_endpoint.md +186 -101
- data/doc/plugins/derivatives.md +839 -0
- data/doc/plugins/determine_mime_type.md +4 -2
- data/doc/plugins/download_endpoint.md +64 -8
- data/doc/plugins/dynamic_storage.md +5 -3
- data/doc/plugins/entity.md +263 -0
- data/doc/plugins/form_assign.md +55 -0
- data/doc/plugins/included.md +31 -8
- data/doc/plugins/infer_extension.md +21 -10
- data/doc/plugins/instrumentation.md +38 -16
- data/doc/plugins/keep_files.md +16 -17
- data/doc/plugins/metadata_attributes.md +42 -13
- data/doc/plugins/mirroring.md +118 -0
- data/doc/plugins/model.md +210 -0
- data/doc/plugins/module_include.md +4 -2
- data/doc/plugins/multi_cache.md +24 -0
- data/doc/plugins/persistence.md +101 -0
- data/doc/plugins/presign_endpoint.md +9 -4
- data/doc/plugins/pretty_location.md +16 -3
- data/doc/plugins/processing.md +4 -2
- data/doc/plugins/rack_file.md +8 -2
- data/doc/plugins/rack_response.md +6 -2
- data/doc/plugins/recache.md +4 -2
- data/doc/plugins/refresh_metadata.md +49 -9
- data/doc/plugins/remote_url.md +84 -47
- data/doc/plugins/remove_attachment.md +27 -6
- data/doc/plugins/remove_invalid.md +21 -6
- data/doc/plugins/restore_cached_data.md +11 -3
- data/doc/plugins/sequel.md +159 -35
- data/doc/plugins/signature.md +16 -5
- data/doc/plugins/store_dimensions.md +14 -2
- data/doc/plugins/tempfile.md +4 -2
- data/doc/plugins/type_predicates.md +96 -0
- data/doc/plugins/upload_endpoint.md +13 -13
- data/doc/plugins/upload_options.md +6 -4
- data/doc/plugins/{default_url_options.md → url_options.md} +9 -7
- data/doc/plugins/validation.md +97 -0
- data/doc/plugins/validation_helpers.md +16 -13
- data/doc/plugins/versions.md +15 -19
- data/doc/processing.md +438 -221
- data/doc/refile.md +188 -170
- data/doc/release_notes/1.0.0.md +4 -0
- data/doc/release_notes/1.1.0.md +6 -2
- data/doc/release_notes/1.2.0.md +4 -0
- data/doc/release_notes/1.3.0.md +4 -0
- data/doc/release_notes/1.4.0.md +4 -0
- data/doc/release_notes/1.4.1.md +4 -0
- data/doc/release_notes/1.4.2.md +4 -0
- data/doc/release_notes/2.0.0.md +4 -0
- data/doc/release_notes/2.0.1.md +4 -0
- data/doc/release_notes/2.1.0.md +5 -1
- data/doc/release_notes/2.1.1.md +4 -0
- data/doc/release_notes/2.10.0.md +4 -0
- data/doc/release_notes/2.10.1.md +4 -0
- data/doc/release_notes/2.11.0.md +4 -0
- data/doc/release_notes/2.12.0.md +4 -0
- data/doc/release_notes/2.13.0.md +4 -0
- data/doc/release_notes/2.14.0.md +5 -1
- data/doc/release_notes/2.15.0.md +11 -7
- data/doc/release_notes/2.16.0.md +4 -0
- data/doc/release_notes/2.17.0.md +4 -0
- data/doc/release_notes/2.18.0.md +4 -0
- data/doc/release_notes/2.19.0.md +6 -3
- data/doc/release_notes/2.2.0.md +4 -0
- data/doc/release_notes/2.3.0.md +4 -0
- data/doc/release_notes/2.3.1.md +4 -0
- data/doc/release_notes/2.4.0.md +4 -0
- data/doc/release_notes/2.4.1.md +4 -0
- data/doc/release_notes/2.5.0.md +4 -0
- data/doc/release_notes/2.6.0.md +4 -0
- data/doc/release_notes/2.6.1.md +4 -0
- data/doc/release_notes/2.7.0.md +4 -0
- data/doc/release_notes/2.8.0.md +4 -0
- data/doc/release_notes/2.9.0.md +4 -0
- data/doc/release_notes/3.0.0.md +981 -0
- data/doc/release_notes/3.0.1.md +22 -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/release_notes/3.4.0.md +35 -0
- data/doc/release_notes/3.5.0.md +63 -0
- data/doc/release_notes/3.6.0.md +23 -0
- data/doc/retrieving_uploads.md +5 -2
- data/doc/securing_uploads.md +60 -37
- data/doc/storage/file_system.md +20 -3
- data/doc/storage/memory.md +19 -0
- data/doc/storage/s3.md +122 -78
- data/doc/testing.md +141 -133
- data/doc/upgrading_to_3.md +708 -0
- data/doc/validation.md +54 -90
- data/lib/shrine/attacher.rb +292 -169
- data/lib/shrine/attachment.rb +13 -46
- data/lib/shrine/plugins/_persistence.rb +93 -0
- data/lib/shrine/plugins/activerecord.rb +77 -34
- data/lib/shrine/plugins/add_metadata.rb +25 -17
- data/lib/shrine/plugins/atomic_helpers.rb +119 -0
- data/lib/shrine/plugins/backgrounding.rb +77 -113
- data/lib/shrine/plugins/cached_attachment_data.rb +6 -15
- data/lib/shrine/plugins/column.rb +102 -0
- data/lib/shrine/plugins/data_uri.rb +38 -36
- data/lib/shrine/plugins/default_storage.rb +45 -15
- data/lib/shrine/plugins/default_url.rb +12 -24
- data/lib/shrine/plugins/default_url_options.rb +3 -30
- data/lib/shrine/plugins/delete_raw.rb +10 -16
- data/lib/shrine/plugins/derivation_endpoint.rb +130 -171
- data/lib/shrine/plugins/derivatives.rb +645 -0
- data/lib/shrine/plugins/determine_mime_type.rb +9 -21
- data/lib/shrine/plugins/download_endpoint.rb +118 -133
- data/lib/shrine/plugins/dynamic_storage.rb +5 -11
- data/lib/shrine/plugins/entity.rb +158 -0
- data/lib/shrine/plugins/form_assign.rb +108 -0
- data/lib/shrine/plugins/included.rb +6 -6
- data/lib/shrine/plugins/infer_extension.rb +17 -20
- data/lib/shrine/plugins/instrumentation.rb +59 -43
- data/lib/shrine/plugins/keep_files.rb +3 -15
- data/lib/shrine/plugins/metadata_attributes.rb +28 -19
- data/lib/shrine/plugins/mirroring.rb +142 -0
- data/lib/shrine/plugins/model.rb +160 -0
- data/lib/shrine/plugins/module_include.rb +3 -3
- data/lib/shrine/plugins/multi_cache.rb +27 -0
- data/lib/shrine/plugins/presign_endpoint.rb +27 -28
- data/lib/shrine/plugins/pretty_location.rb +15 -9
- data/lib/shrine/plugins/processing.rb +22 -9
- data/lib/shrine/plugins/rack_file.rb +2 -42
- data/lib/shrine/plugins/rack_response.rb +21 -10
- data/lib/shrine/plugins/recache.rb +6 -5
- data/lib/shrine/plugins/refresh_metadata.rb +13 -11
- data/lib/shrine/plugins/remote_url.rb +49 -49
- data/lib/shrine/plugins/remove_attachment.rb +12 -6
- data/lib/shrine/plugins/remove_invalid.rb +19 -8
- data/lib/shrine/plugins/restore_cached_data.rb +13 -7
- data/lib/shrine/plugins/sequel.rb +86 -36
- data/lib/shrine/plugins/signature.rb +10 -16
- data/lib/shrine/plugins/store_dimensions.rb +35 -40
- data/lib/shrine/plugins/tempfile.rb +1 -3
- data/lib/shrine/plugins/type_predicates.rb +113 -0
- data/lib/shrine/plugins/upload_endpoint.rb +28 -24
- data/lib/shrine/plugins/upload_options.rb +14 -15
- data/lib/shrine/plugins/url_options.rb +31 -0
- data/lib/shrine/plugins/validation.rb +80 -0
- data/lib/shrine/plugins/validation_helpers.rb +35 -58
- data/lib/shrine/plugins/versions.rb +107 -87
- data/lib/shrine/plugins.rb +22 -0
- data/lib/shrine/storage/file_system.rb +46 -64
- data/lib/shrine/storage/linter.rb +42 -7
- data/lib/shrine/storage/memory.rb +49 -0
- data/lib/shrine/storage/s3.rb +173 -160
- data/lib/shrine/uploaded_file.rb +32 -32
- data/lib/shrine/version.rb +3 -3
- data/lib/shrine.rb +87 -150
- data/shrine.gemspec +11 -12
- metadata +92 -82
- data/doc/migrating_storage.md +0 -76
- data/doc/plugins/backup.md +0 -31
- data/doc/plugins/copy.md +0 -24
- data/doc/plugins/delete_promoted.md +0 -12
- data/doc/plugins/direct_upload.md +0 -172
- data/doc/plugins/hooks.md +0 -58
- data/doc/plugins/logging.md +0 -42
- data/doc/plugins/migration_helpers.md +0 -60
- data/doc/plugins/moving.md +0 -19
- data/doc/plugins/multi_delete.md +0 -20
- data/doc/plugins/parallelize.md +0 -16
- data/doc/plugins/parsed_json.md +0 -23
- data/doc/regenerating_versions.md +0 -143
- data/lib/shrine/plugins/background_helpers.rb +0 -5
- data/lib/shrine/plugins/backup.rb +0 -90
- data/lib/shrine/plugins/copy.rb +0 -50
- data/lib/shrine/plugins/delete_promoted.rb +0 -20
- data/lib/shrine/plugins/direct_upload.rb +0 -217
- data/lib/shrine/plugins/hooks.rb +0 -90
- data/lib/shrine/plugins/logging.rb +0 -142
- data/lib/shrine/plugins/migration_helpers.rb +0 -70
- data/lib/shrine/plugins/moving.rb +0 -57
- data/lib/shrine/plugins/multi_delete.rb +0 -32
- data/lib/shrine/plugins/parallelize.rb +0 -78
- data/lib/shrine/plugins/parsed_json.rb +0 -29
|
@@ -0,0 +1,708 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: upgrading-to-3
|
|
3
|
+
title: Upgrading to Shrine 3.x
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
This guide provides instructions for upgrading Shrine in your apps to version
|
|
7
|
+
3.x. If you're looking for a full list of changes, see the **[3.0 release
|
|
8
|
+
notes]**.
|
|
9
|
+
|
|
10
|
+
## Attacher
|
|
11
|
+
|
|
12
|
+
The `Shrine::Attacher` class has been rewritten in Shrine 3.0, though much of
|
|
13
|
+
the main API remained the same.
|
|
14
|
+
|
|
15
|
+
### Model
|
|
16
|
+
|
|
17
|
+
The main change is that `Attacher.new` is now used for initializing the
|
|
18
|
+
attacher without a model:
|
|
19
|
+
|
|
20
|
+
```rb
|
|
21
|
+
attacher = Shrine::Attacher.new
|
|
22
|
+
#=> #<Shrine::Attacher>
|
|
23
|
+
|
|
24
|
+
attacher = Shrine::Attacher.new(photo, :image)
|
|
25
|
+
# ~> ArgumentError: invalid number of arguments
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
To initialize an attacher with a model, use `Attacher.from_model` provided by
|
|
29
|
+
the new [`model`][model] plugin (which is automatically loaded by
|
|
30
|
+
`activerecord` and `sequel` plugins):
|
|
31
|
+
|
|
32
|
+
```rb
|
|
33
|
+
attacher = Shrine::Attacher.from_model(photo, :image)
|
|
34
|
+
# ...
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
If you're using the `Shrine::Attachment` module with POROs, make sure to load
|
|
38
|
+
the `model` plugin.
|
|
39
|
+
|
|
40
|
+
```rb
|
|
41
|
+
Shrine.plugin :model
|
|
42
|
+
```
|
|
43
|
+
```rb
|
|
44
|
+
class Photo < Struct.new(:image_data)
|
|
45
|
+
include Shrine::Attachment(:image)
|
|
46
|
+
end
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Data attribute
|
|
50
|
+
|
|
51
|
+
The `Attacher#read` method has been removed. If you want to generate serialized
|
|
52
|
+
attachment data, use `Attacher#column_data`. Otherwise if you want to generate
|
|
53
|
+
hash attachment data, use `Attacher#data`.
|
|
54
|
+
|
|
55
|
+
```rb
|
|
56
|
+
attacher.column_data #=> '{"id":"...","storage":"...","metadata":{...}}'
|
|
57
|
+
attacher.data #=> { "id" => "...", "storage" => "...", "metadata" => { ... } }
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
The `Attacher#data_attribute` has been renamed to `Attacher#attribute`.
|
|
61
|
+
|
|
62
|
+
### State
|
|
63
|
+
|
|
64
|
+
The attacher now maintains its own state, so if you've previously modified the
|
|
65
|
+
`#<name>_data` record attribute and expected the changes to be picked up by the
|
|
66
|
+
attacher, you'll now need to call `Attacher#reload` for that:
|
|
67
|
+
|
|
68
|
+
```rb
|
|
69
|
+
attacher.file #=> nil
|
|
70
|
+
record.image_data = '{"id":"...","storage":"...","metadata":{...}}'
|
|
71
|
+
attacher.file #=> nil
|
|
72
|
+
attacher.reload
|
|
73
|
+
attacher.file #=> #<Shrine::UploadedFile ...>
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Assigning
|
|
77
|
+
|
|
78
|
+
The `Attacher#assign` method now raises an exception when non-cached uploaded
|
|
79
|
+
file data is assigned:
|
|
80
|
+
|
|
81
|
+
```rb
|
|
82
|
+
# Shrine 2.x
|
|
83
|
+
attacher.assign('{"id": "...", "storage": "store", "metadata": {...}}') # ignored
|
|
84
|
+
|
|
85
|
+
# Shrine 3.0
|
|
86
|
+
attacher.assign('{"id": "...", "storage": "store", "metadata": {...}}')
|
|
87
|
+
#~> Shrine::Error: expected cached file, got #<Shrine::UploadedFile storage=:store ...>
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Validation
|
|
91
|
+
|
|
92
|
+
The validation functionality has been extracted into the `validation` plugin.
|
|
93
|
+
If you're using the `validation_helpers` plugin, it will automatically load
|
|
94
|
+
`validation` for you. Otherwise you'll have to load it explicitly:
|
|
95
|
+
|
|
96
|
+
```rb
|
|
97
|
+
Shrine.plugin :validation
|
|
98
|
+
```
|
|
99
|
+
```rb
|
|
100
|
+
class MyUploader < Shrine
|
|
101
|
+
Attacher.validate do
|
|
102
|
+
# ...
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Setting
|
|
108
|
+
|
|
109
|
+
The `Attacher#set` method has been renamed to `Attacher#change`, and the
|
|
110
|
+
private `Attacher#_set` method has been renamed to `Attacher#set` and made
|
|
111
|
+
public:
|
|
112
|
+
|
|
113
|
+
```rb
|
|
114
|
+
attacher.change(uploaded_file) # sets file, remembers previous file, runs validations
|
|
115
|
+
attacher.set(uploaded_file) # sets file
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
If you've previously used `Attacher#replace` directly to delete previous file,
|
|
119
|
+
it has now been renamed to `Attacher#destroy_previous`.
|
|
120
|
+
|
|
121
|
+
Also note that `Attacher#attached?` now returns whether a file is attached,
|
|
122
|
+
while `Attacher#changed?` continues to return whether the attachment has
|
|
123
|
+
changed.
|
|
124
|
+
|
|
125
|
+
### Uploading and deleting
|
|
126
|
+
|
|
127
|
+
The `Attacher#store!` and `Attacher#cache!` methods have been removed, you
|
|
128
|
+
should now use `Attacher#upload` instead:
|
|
129
|
+
|
|
130
|
+
```rb
|
|
131
|
+
attacher.upload(io) # uploads to permanent storage
|
|
132
|
+
attacher.upload(io, :cache) # uploads to temporary storage
|
|
133
|
+
attacher.upload(io, :other_store) # uploads to another storage
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
The `Attacher#delete!` method has been removed as well, you should instead just
|
|
137
|
+
delete the file directly via `UploadedFile#delete`.
|
|
138
|
+
|
|
139
|
+
### Promoting
|
|
140
|
+
|
|
141
|
+
If you were promoting manually, the `Attacher#promote` method will now only
|
|
142
|
+
save promoted file in memory, it won't persist the changes.
|
|
143
|
+
|
|
144
|
+
```rb
|
|
145
|
+
attacher.promote
|
|
146
|
+
# ...
|
|
147
|
+
record.save # you need to persist the changes
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
If you want the concurrenct-safe promotion with persistence, use the new
|
|
151
|
+
`Attacher#atomic_promote` method.
|
|
152
|
+
|
|
153
|
+
```rb
|
|
154
|
+
attacher.atomic_promote
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
The `Attacher#swap` method has been removed. If you were using it directly, you
|
|
158
|
+
can use `Attacher#set` and `Attacher#atomic_persist` instead:
|
|
159
|
+
|
|
160
|
+
```rb
|
|
161
|
+
current_file = attacher.file
|
|
162
|
+
attacher.set(new_file)
|
|
163
|
+
attacher.atomic_persist(current_file)
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Backgrounding
|
|
167
|
+
|
|
168
|
+
The `backgrounding` plugin has been rewritten in Shrine 3.0 and has a new API.
|
|
169
|
+
|
|
170
|
+
```rb
|
|
171
|
+
Shrine.plugin :backgrounding
|
|
172
|
+
Shrine::Attacher.promote_block do
|
|
173
|
+
PromoteJob.perform_async(self.class.name, record.class.name, record.id, name, file_data)
|
|
174
|
+
end
|
|
175
|
+
Shrine::Attacher.destroy_block do
|
|
176
|
+
DestroyJob.perform_async(self.class.name, data)
|
|
177
|
+
end
|
|
178
|
+
```
|
|
179
|
+
```rb
|
|
180
|
+
class PromoteJob
|
|
181
|
+
include Sidekiq::Worker
|
|
182
|
+
|
|
183
|
+
def perform(attacher_class, record_class, record_id, name, file_data)
|
|
184
|
+
attacher_class = Object.const_get(attacher_class)
|
|
185
|
+
record = Object.const_get(record_class).find(record_id) # if using Active Record
|
|
186
|
+
|
|
187
|
+
attacher = attacher_class.retrieve(model: record, name: name, file: file_data)
|
|
188
|
+
attacher.atomic_promote
|
|
189
|
+
rescue Shrine::AttachmentChanged, ActiveRecord::RecordNotFound
|
|
190
|
+
# attachment has changed or record has been deleted, nothing to do
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
```
|
|
194
|
+
```rb
|
|
195
|
+
class DestroyJob
|
|
196
|
+
include Sidekiq::Worker
|
|
197
|
+
|
|
198
|
+
def perform(attacher_class, data)
|
|
199
|
+
attacher_class = Object.const_get(attacher_class)
|
|
200
|
+
|
|
201
|
+
attacher = attacher_class.from_data(data)
|
|
202
|
+
attacher.destroy
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Dual support
|
|
208
|
+
|
|
209
|
+
When you're making the switch in production, there might still be jobs in the
|
|
210
|
+
queue that have the old argument format. So, we'll initially want to handle
|
|
211
|
+
both argument formats, and then switch to the new one once the jobs with old
|
|
212
|
+
format have been drained.
|
|
213
|
+
|
|
214
|
+
```rb
|
|
215
|
+
class PromoteJob
|
|
216
|
+
include Sidekiq::Worker
|
|
217
|
+
|
|
218
|
+
def perform(*args)
|
|
219
|
+
if args.one?
|
|
220
|
+
file_data, (record_class, record_id), name, shrine_class =
|
|
221
|
+
args.first.values_at("attachment", "record", "name", "shrine_class")
|
|
222
|
+
|
|
223
|
+
record = Object.const_get(record_class).find(record_id) # if using Active Record
|
|
224
|
+
attacher_class = Object.const_get(shrine_class)::Attacher
|
|
225
|
+
else
|
|
226
|
+
attacher_class, record_class, record_id, name, file_data = args
|
|
227
|
+
|
|
228
|
+
attacher_class = Object.const_get(attacher_class)
|
|
229
|
+
record = Object.const_get(record_class).find(record_id) # if using Active Record
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
attacher = attacher_class.retrieve(model: record, name: name, file: file_data)
|
|
233
|
+
attacher.atomic_promote
|
|
234
|
+
rescue Shrine::AttachmentChanged, ActiveRecord::RecordNotFound
|
|
235
|
+
# attachment has changed or record has been deleted, nothing to do
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
```
|
|
239
|
+
```rb
|
|
240
|
+
class DestroyJob
|
|
241
|
+
include Sidekiq::Worker
|
|
242
|
+
|
|
243
|
+
def perform(*args)
|
|
244
|
+
if args.one?
|
|
245
|
+
data, shrine_class = args.first.values_at("attachment", "shrine_class")
|
|
246
|
+
|
|
247
|
+
data = JSON.parse(data)
|
|
248
|
+
attacher_class = Object.const_get(shrine_class)::Attacher
|
|
249
|
+
else
|
|
250
|
+
attacher_class, data = args
|
|
251
|
+
|
|
252
|
+
attacher_class = Object.const_get(attacher_class)
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
attacher = attacher_class.from_data(data)
|
|
256
|
+
attacher.destroy
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### Attacher backgrounding
|
|
262
|
+
|
|
263
|
+
In Shrine 2.x, `Attacher#_promote` and `Attacher#_delete` methods could be used
|
|
264
|
+
to spawn promote and delete jobs. This is now done by `Attacher#promote_cached`
|
|
265
|
+
and `Attacher#destroy_attached`:
|
|
266
|
+
|
|
267
|
+
```rb
|
|
268
|
+
attacher.promote_cached # will spawn background job if registered
|
|
269
|
+
attacher.destroy_attached # will spawn background job if registered
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
If you want to explicitly call backgrounding blocks, you can use
|
|
273
|
+
`Attacher#promote_background` and `Attacher#destroy_background`:
|
|
274
|
+
|
|
275
|
+
```rb
|
|
276
|
+
attacher.promote_background # calls promote block
|
|
277
|
+
attacher.destroy_background # calls destroy block
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
## Versions
|
|
281
|
+
|
|
282
|
+
The `versions`, `processing`, `recache`, and `delete_raw` plugins have been
|
|
283
|
+
deprecated in favour of the new **[`derivatives`][derivatives]** plugin.
|
|
284
|
+
|
|
285
|
+
Let's assume you have the following `versions` configuration:
|
|
286
|
+
|
|
287
|
+
```rb
|
|
288
|
+
class ImageUploader < Shrine
|
|
289
|
+
plugin :processing
|
|
290
|
+
plugin :versions
|
|
291
|
+
plugin :delete_raw
|
|
292
|
+
|
|
293
|
+
process(:store) do |file, context|
|
|
294
|
+
versions = { original: file }
|
|
295
|
+
|
|
296
|
+
file.download do |original|
|
|
297
|
+
magick = ImageProcessing::MiniMagick.source(original)
|
|
298
|
+
|
|
299
|
+
versions[:large] = magick.resize_to_limit!(800, 800)
|
|
300
|
+
versions[:medium] = magick.resize_to_limit!(500, 500)
|
|
301
|
+
versions[:small] = magick.resize_to_limit!(300, 300)
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
versions
|
|
305
|
+
end
|
|
306
|
+
end
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
When an attached file is promoted to permanent storage, the versions would
|
|
310
|
+
automatically get generated:
|
|
311
|
+
|
|
312
|
+
```rb
|
|
313
|
+
photo = Photo.new(photo_params)
|
|
314
|
+
|
|
315
|
+
if photo.valid?
|
|
316
|
+
photo.save # generates versions on promotion
|
|
317
|
+
# ...
|
|
318
|
+
else
|
|
319
|
+
# ...
|
|
320
|
+
end
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
With `derivatives`, the original file is automatically downloaded and retained
|
|
324
|
+
during processing, so the setup is simpler:
|
|
325
|
+
|
|
326
|
+
```rb
|
|
327
|
+
Shrine.plugin :derivatives,
|
|
328
|
+
create_on_promote: true, # automatically create derivatives on promotion
|
|
329
|
+
versions_compatibility: true # handle versions column format
|
|
330
|
+
```
|
|
331
|
+
```rb
|
|
332
|
+
class ImageUploader < Shrine
|
|
333
|
+
Attacher.derivatives do |original|
|
|
334
|
+
magick = ImageProcessing::MiniMagick.source(original)
|
|
335
|
+
|
|
336
|
+
# the :original file should NOT be included anymore
|
|
337
|
+
{
|
|
338
|
+
large: magick.resize_to_limit!(800, 800),
|
|
339
|
+
medium: magick.resize_to_limit!(500, 500),
|
|
340
|
+
small: magick.resize_to_limit!(300, 300),
|
|
341
|
+
}
|
|
342
|
+
end
|
|
343
|
+
end
|
|
344
|
+
```
|
|
345
|
+
```rb
|
|
346
|
+
photo = Photo.new(photo_params)
|
|
347
|
+
|
|
348
|
+
if photo.valid?
|
|
349
|
+
photo.save # creates derivatives on promotion
|
|
350
|
+
# ...
|
|
351
|
+
else
|
|
352
|
+
# ...
|
|
353
|
+
end
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
### Accessing derivatives
|
|
357
|
+
|
|
358
|
+
The derivative URLs are accessed in the same way as versions:
|
|
359
|
+
|
|
360
|
+
```rb
|
|
361
|
+
photo.image_url(:small)
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
But the files themselves are accessed differently:
|
|
365
|
+
|
|
366
|
+
```rb
|
|
367
|
+
# versions
|
|
368
|
+
photo.image #=>
|
|
369
|
+
# {
|
|
370
|
+
# original: #<Shrine::UploadedFile ...>,
|
|
371
|
+
# large: #<Shrine::UploadedFile ...>,
|
|
372
|
+
# medium: #<Shrine::UploadedFile ...>,
|
|
373
|
+
# small: #<Shrine::UploadedFile ...>,
|
|
374
|
+
# }
|
|
375
|
+
photo.image[:medium] #=> #<Shrine::UploadedFile ...>
|
|
376
|
+
```
|
|
377
|
+
```rb
|
|
378
|
+
# derivatives
|
|
379
|
+
photo.image_derivatives #=>
|
|
380
|
+
# {
|
|
381
|
+
# large: #<Shrine::UploadedFile ...>,
|
|
382
|
+
# medium: #<Shrine::UploadedFile ...>,
|
|
383
|
+
# small: #<Shrine::UploadedFile ...>,
|
|
384
|
+
# }
|
|
385
|
+
photo.image(:medium) #=> #<Shrine::UploadedFile ...>
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
### Migrating versions
|
|
389
|
+
|
|
390
|
+
The `versions` and `derivatives` plugins save processed file data to the
|
|
391
|
+
database column in different formats:
|
|
392
|
+
|
|
393
|
+
```rb
|
|
394
|
+
# versions
|
|
395
|
+
{
|
|
396
|
+
"original": { "id": "...", "storage": "...", "metadata": { ... } },
|
|
397
|
+
"large": { "id": "...", "storage": "...", "metadata": { ... } },
|
|
398
|
+
"medium": { "id": "...", "storage": "...", "metadata": { ... } },
|
|
399
|
+
"small": { "id": "...", "storage": "...", "metadata": { ... } }
|
|
400
|
+
}
|
|
401
|
+
```
|
|
402
|
+
```rb
|
|
403
|
+
# derivatives
|
|
404
|
+
{
|
|
405
|
+
"id": "...",
|
|
406
|
+
"storage": "...",
|
|
407
|
+
"metadata": { ... },
|
|
408
|
+
"derivatives": {
|
|
409
|
+
"large": { "id": "...", "storage": "...", "metadata": { ... } },
|
|
410
|
+
"medium": { "id": "...", "storage": "...", "metadata": { ... } },
|
|
411
|
+
"small": { "id": "...", "storage": "...", "metadata": { ... } }
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
The `:versions_compatibility` flag to the `derivatives` plugin enables it to
|
|
417
|
+
read the `versions` format, which aids in transition. Once the `derivatives`
|
|
418
|
+
plugin has been deployed to production, you can update existing records with
|
|
419
|
+
the new column format:
|
|
420
|
+
|
|
421
|
+
```rb
|
|
422
|
+
Photo.find_each do |photo|
|
|
423
|
+
photo.image_attacher.write
|
|
424
|
+
photo.image_attacher.atomic_persist
|
|
425
|
+
end
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
Afterwards you should be able to remove the `:versions_compatibility` flag.
|
|
429
|
+
|
|
430
|
+
### Backgrounding derivatives
|
|
431
|
+
|
|
432
|
+
If you're using the `backgrounding` plugin, you can trigger derivatives
|
|
433
|
+
creation in the `PromoteJob` instead of the controller:
|
|
434
|
+
|
|
435
|
+
```rb
|
|
436
|
+
class PromoteJob
|
|
437
|
+
include Sidekiq::Worker
|
|
438
|
+
|
|
439
|
+
def perform(attacher_class, record_class, record_id, name, file_data)
|
|
440
|
+
attacher_class = Object.const_get(attacher_class)
|
|
441
|
+
record = Object.const_get(record_class).find(record_id) # if using Active Record
|
|
442
|
+
|
|
443
|
+
attacher = attacher_class.retrieve(model: record, name: name, file: file_data)
|
|
444
|
+
attacher.create_derivatives # call derivatives processor
|
|
445
|
+
attacher.atomic_promote
|
|
446
|
+
rescue Shrine::AttachmentChanged, ActiveRecord::RecordNotFound
|
|
447
|
+
# attachment has changed or record has been deleted, nothing to do
|
|
448
|
+
end
|
|
449
|
+
end
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
#### Recache
|
|
453
|
+
|
|
454
|
+
If you were using the `recache` plugin, you can replicate the behaviour by
|
|
455
|
+
creating another derivatives processor that you will trigger in the controller:
|
|
456
|
+
|
|
457
|
+
```rb
|
|
458
|
+
class ImageUploader < Shrine
|
|
459
|
+
Attacher.derivatives do |original|
|
|
460
|
+
# this will be triggered in the background job
|
|
461
|
+
end
|
|
462
|
+
|
|
463
|
+
Attacher.derivatives :foreground do |original|
|
|
464
|
+
# this will be triggered in the controller
|
|
465
|
+
end
|
|
466
|
+
end
|
|
467
|
+
```
|
|
468
|
+
```rb
|
|
469
|
+
photo = Photo.new(photo_params)
|
|
470
|
+
|
|
471
|
+
if photo.valid?
|
|
472
|
+
photo.image_derivatives!(:foreground) if photo.image_changed?
|
|
473
|
+
photo.save
|
|
474
|
+
# ...
|
|
475
|
+
else
|
|
476
|
+
# ...
|
|
477
|
+
end
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
### Default URL
|
|
481
|
+
|
|
482
|
+
If you were using the `default_url` plugin, the `Attacher.default_url` now
|
|
483
|
+
receives a `:derivative` option:
|
|
484
|
+
|
|
485
|
+
```rb
|
|
486
|
+
Attacher.default_url do |derivative: nil, **|
|
|
487
|
+
"https://my-app.com/fallbacks/#{derivative}.jpg" if derivative
|
|
488
|
+
end
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
#### Fallback to original
|
|
492
|
+
|
|
493
|
+
With the `versions` plugin, a missing version URL would automatically fall back
|
|
494
|
+
to the original file. The `derivatives` plugin has no such fallback, but you
|
|
495
|
+
can configure it manually:
|
|
496
|
+
|
|
497
|
+
```rb
|
|
498
|
+
Attacher.default_url do |derivative: nil, **|
|
|
499
|
+
file&.url if derivative
|
|
500
|
+
end
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
#### Fallback to version
|
|
504
|
+
|
|
505
|
+
The `versions` plugin had the ability to fall back missing version URL to
|
|
506
|
+
another version that already exists. The `derivatives` plugin doesn't have this
|
|
507
|
+
built in, but you can implement it as follows:
|
|
508
|
+
|
|
509
|
+
```rb
|
|
510
|
+
DERIVATIVE_FALLBACKS = { foo: :bar, ... }
|
|
511
|
+
|
|
512
|
+
Attacher.default_url do |derivative: nil, **|
|
|
513
|
+
derivatives[DERIVATIVE_FALLBACKS[derivative]]&.url if derivative
|
|
514
|
+
end
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
### Location
|
|
518
|
+
|
|
519
|
+
The `Shrine#generate_location` method will now receive a `:derivative`
|
|
520
|
+
parameter instead of `:version`:
|
|
521
|
+
|
|
522
|
+
```rb
|
|
523
|
+
class MyUploader < Shrine
|
|
524
|
+
def generate_location(io, derivative: nil, **)
|
|
525
|
+
derivative #=> :large, :medium, :small, ...
|
|
526
|
+
# ...
|
|
527
|
+
end
|
|
528
|
+
end
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
### Overwriting original
|
|
532
|
+
|
|
533
|
+
With the `derivatives` plugin, saving processed files separately from the
|
|
534
|
+
original file, so the original file is automatically kept. This means it's not
|
|
535
|
+
possible anymore to overwrite the original file as part of processing.
|
|
536
|
+
|
|
537
|
+
However, **it's highly recommended to always keep the original file**, even if
|
|
538
|
+
you don't plan to use it. That way, if there is ever a need to reprocess
|
|
539
|
+
derivatives, you have the original file to use as a base.
|
|
540
|
+
|
|
541
|
+
That being said, if you still want to overwrite the original file, [this
|
|
542
|
+
thread][overwriting original] has some tips.
|
|
543
|
+
|
|
544
|
+
## Other
|
|
545
|
+
|
|
546
|
+
### Processing
|
|
547
|
+
|
|
548
|
+
The `processing` plugin has been deprecated over the new
|
|
549
|
+
[`derivatives`][derivatives] plugin. If you were previously replacing the
|
|
550
|
+
original file:
|
|
551
|
+
|
|
552
|
+
```rb
|
|
553
|
+
class MyUploader < Shrine
|
|
554
|
+
plugin :processing
|
|
555
|
+
|
|
556
|
+
process(:store) do |io, context|
|
|
557
|
+
ImageProcessing::MiniMagick
|
|
558
|
+
.source(io.download)
|
|
559
|
+
.resize_to_limit!(1600, 1600)
|
|
560
|
+
end
|
|
561
|
+
end
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
you should now add the processed file as a derivative:
|
|
565
|
+
|
|
566
|
+
```rb
|
|
567
|
+
class MyUploader < Shrine
|
|
568
|
+
plugin :derivatives
|
|
569
|
+
|
|
570
|
+
Attacher.derivatives do |original|
|
|
571
|
+
magick = ImageProcessing::MiniMagick.source(original)
|
|
572
|
+
|
|
573
|
+
{ normalized: magick.resize_to_limit!(1600, 1600) }
|
|
574
|
+
end
|
|
575
|
+
end
|
|
576
|
+
```
|
|
577
|
+
|
|
578
|
+
### Parallelize
|
|
579
|
+
|
|
580
|
+
The `parallelize` plugin has been removed. With `derivatives` plugin you can
|
|
581
|
+
parallelize uploading processed files manually:
|
|
582
|
+
|
|
583
|
+
```rb
|
|
584
|
+
# Gemfile
|
|
585
|
+
gem "concurrent-ruby"
|
|
586
|
+
```
|
|
587
|
+
```rb
|
|
588
|
+
require "concurrent"
|
|
589
|
+
|
|
590
|
+
attacher = photo.image_attacher
|
|
591
|
+
derivatives = attacher.process_derivatives
|
|
592
|
+
|
|
593
|
+
tasks = derivatives.map do |name, file|
|
|
594
|
+
Concurrent::Promises.future(name, file) do |name, file|
|
|
595
|
+
attacher.add_derivative(name, file)
|
|
596
|
+
end
|
|
597
|
+
end
|
|
598
|
+
|
|
599
|
+
Concurrent::Promises.zip(*tasks).wait!
|
|
600
|
+
```
|
|
601
|
+
|
|
602
|
+
### Logging
|
|
603
|
+
|
|
604
|
+
The `logging` plugin has been removed in favour of the
|
|
605
|
+
[`instrumentation`][instrumentation] plugin. You can replace code like
|
|
606
|
+
|
|
607
|
+
```rb
|
|
608
|
+
Shrine.plugin :logging, logger: Rails.logger
|
|
609
|
+
```
|
|
610
|
+
|
|
611
|
+
with
|
|
612
|
+
|
|
613
|
+
```rb
|
|
614
|
+
Shrine.logger = Rails.logger
|
|
615
|
+
|
|
616
|
+
Shrine.plugin :instrumentation
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
### Backup
|
|
620
|
+
|
|
621
|
+
The `backup` plugin has been removed in favour of the new
|
|
622
|
+
[`mirroring`][mirroring] plugin. You can replace code like
|
|
623
|
+
|
|
624
|
+
```rb
|
|
625
|
+
Shrine.plugin :backup, storage: :backup_store
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
with
|
|
629
|
+
|
|
630
|
+
```rb
|
|
631
|
+
Shrine.plugin :mirroring, mirror: { store: :backup_store }
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
### Copy
|
|
635
|
+
|
|
636
|
+
The `copy` plugin has been removed as its behaviour can now be achieved easily.
|
|
637
|
+
You can replace code like
|
|
638
|
+
|
|
639
|
+
```rb
|
|
640
|
+
Shrine.plugin :copy
|
|
641
|
+
```
|
|
642
|
+
```rb
|
|
643
|
+
attacher.copy(other_attacher)
|
|
644
|
+
```
|
|
645
|
+
|
|
646
|
+
with
|
|
647
|
+
|
|
648
|
+
```rb
|
|
649
|
+
attacher.set nil # clear original attachment
|
|
650
|
+
attacher.attach other_attacher.file, storage: other_attacher.file.storage_key
|
|
651
|
+
attacher.add_derivatives other_attacher.derivatives # if using derivatives
|
|
652
|
+
```
|
|
653
|
+
|
|
654
|
+
### Moving
|
|
655
|
+
|
|
656
|
+
The `moving` plugin has been removed in favour of the `:move` option for
|
|
657
|
+
`FileSystem#upload`. You can set this option as default using the
|
|
658
|
+
`upload_options` plugin (the example assumes both `:cache` and `:store` are
|
|
659
|
+
FileSystem storages):
|
|
660
|
+
|
|
661
|
+
```rb
|
|
662
|
+
Shrine.plugin :upload_options, cache: { move: true }, store: { move: true }
|
|
663
|
+
```
|
|
664
|
+
|
|
665
|
+
### Parsed JSON
|
|
666
|
+
|
|
667
|
+
The `parsed_json` plugin has been removed as it's now the default behaviour.
|
|
668
|
+
|
|
669
|
+
```rb
|
|
670
|
+
# this now works by default
|
|
671
|
+
photo.image = { "id" => "d7e54d6ef2.jpg", "storage" => "cache", "metadata" => { ... } }
|
|
672
|
+
```
|
|
673
|
+
|
|
674
|
+
### Module Include
|
|
675
|
+
|
|
676
|
+
The `module_include` plugin has been deprecated over overriding core classes
|
|
677
|
+
directly. You can replace code like
|
|
678
|
+
|
|
679
|
+
```rb
|
|
680
|
+
class MyUploader < Shrine
|
|
681
|
+
plugin :module_include
|
|
682
|
+
|
|
683
|
+
file_methods do
|
|
684
|
+
def image?
|
|
685
|
+
mime_type.start_with?("image")
|
|
686
|
+
end
|
|
687
|
+
end
|
|
688
|
+
end
|
|
689
|
+
```
|
|
690
|
+
|
|
691
|
+
with
|
|
692
|
+
|
|
693
|
+
```rb
|
|
694
|
+
class MyUploader < Shrine
|
|
695
|
+
class UploadedFile
|
|
696
|
+
def image?
|
|
697
|
+
mime_type.start_with?("image")
|
|
698
|
+
end
|
|
699
|
+
end
|
|
700
|
+
end
|
|
701
|
+
```
|
|
702
|
+
|
|
703
|
+
[3.0 release notes]: https://shrinerb.com/docs/release_notes/3.0.0
|
|
704
|
+
[model]: https://shrinerb.com/docs/plugins/model
|
|
705
|
+
[derivatives]: https://shrinerb.com/docs/plugins/derivatives
|
|
706
|
+
[instrumentation]: https://shrinerb.com/docs/plugins/instrumentation
|
|
707
|
+
[mirroring]: https://shrinerb.com/docs/plugins/mirroring
|
|
708
|
+
[overwriting original]: https://discourse.shrinerb.com/t/keep-original-file-after-processing/50/4
|