shrine 3.0.0 → 3.2.2
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 +87 -33
- data/LICENSE.txt +1 -1
- data/README.md +94 -4
- data/doc/advantages.md +35 -18
- data/doc/attacher.md +16 -17
- data/doc/carrierwave.md +75 -34
- data/doc/changing_derivatives.md +39 -39
- data/doc/design.md +134 -85
- data/doc/external/articles.md +56 -41
- data/doc/external/extensions.md +38 -34
- data/doc/getting_started.md +182 -112
- data/doc/metadata.md +79 -43
- data/doc/multiple_files.md +5 -3
- data/doc/paperclip.md +110 -42
- data/doc/plugins/activerecord.md +5 -5
- data/doc/plugins/add_metadata.md +92 -35
- data/doc/plugins/backgrounding.md +12 -2
- data/doc/plugins/column.md +36 -7
- data/doc/plugins/data_uri.md +2 -2
- data/doc/plugins/default_url.md +6 -3
- data/doc/plugins/derivation_endpoint.md +26 -28
- data/doc/plugins/derivatives.md +205 -169
- data/doc/plugins/determine_mime_type.md +2 -2
- data/doc/plugins/entity.md +3 -3
- data/doc/plugins/form_assign.md +5 -5
- data/doc/plugins/included.md +25 -5
- data/doc/plugins/infer_extension.md +2 -2
- data/doc/plugins/instrumentation.md +1 -1
- data/doc/plugins/metadata_attributes.md +21 -10
- data/doc/plugins/model.md +4 -4
- data/doc/plugins/persistence.md +1 -0
- data/doc/plugins/refresh_metadata.md +5 -4
- data/doc/plugins/remote_url.md +8 -3
- data/doc/plugins/remove_invalid.md +9 -1
- data/doc/plugins/sequel.md +4 -4
- data/doc/plugins/signature.md +11 -2
- data/doc/plugins/store_dimensions.md +2 -2
- data/doc/plugins/type_predicates.md +96 -0
- data/doc/plugins/upload_endpoint.md +7 -11
- data/doc/plugins/upload_options.md +1 -1
- data/doc/plugins/url_options.md +2 -2
- data/doc/plugins/validation.md +14 -4
- data/doc/plugins/validation_helpers.md +3 -3
- data/doc/plugins/versions.md +11 -11
- data/doc/processing.md +289 -125
- data/doc/refile.md +39 -18
- data/doc/release_notes/2.19.0.md +1 -1
- data/doc/release_notes/3.0.0.md +275 -258
- 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 +32 -0
- data/doc/release_notes/3.2.2.md +14 -0
- data/doc/securing_uploads.md +3 -3
- data/doc/storage/file_system.md +1 -1
- data/doc/storage/memory.md +19 -0
- data/doc/storage/s3.md +105 -86
- data/doc/testing.md +2 -2
- data/doc/upgrading_to_3.md +115 -33
- data/doc/validation.md +3 -2
- data/lib/shrine.rb +8 -8
- data/lib/shrine/attacher.rb +19 -14
- data/lib/shrine/attachment.rb +5 -5
- data/lib/shrine/plugins.rb +22 -0
- data/lib/shrine/plugins/add_metadata.rb +12 -3
- data/lib/shrine/plugins/default_storage.rb +6 -6
- data/lib/shrine/plugins/default_url.rb +1 -1
- data/lib/shrine/plugins/derivation_endpoint.rb +10 -6
- data/lib/shrine/plugins/derivatives.rb +19 -17
- data/lib/shrine/plugins/determine_mime_type.rb +3 -3
- data/lib/shrine/plugins/entity.rb +6 -6
- data/lib/shrine/plugins/metadata_attributes.rb +1 -1
- data/lib/shrine/plugins/model.rb +3 -3
- data/lib/shrine/plugins/presign_endpoint.rb +2 -2
- data/lib/shrine/plugins/pretty_location.rb +1 -1
- data/lib/shrine/plugins/processing.rb +1 -1
- data/lib/shrine/plugins/refresh_metadata.rb +2 -2
- data/lib/shrine/plugins/remote_url.rb +3 -3
- data/lib/shrine/plugins/remove_invalid.rb +10 -5
- data/lib/shrine/plugins/signature.rb +7 -6
- data/lib/shrine/plugins/store_dimensions.rb +18 -9
- data/lib/shrine/plugins/type_predicates.rb +113 -0
- data/lib/shrine/plugins/upload_endpoint.rb +3 -3
- data/lib/shrine/plugins/upload_options.rb +2 -2
- data/lib/shrine/plugins/url_options.rb +2 -2
- data/lib/shrine/plugins/validation.rb +9 -7
- data/lib/shrine/storage/linter.rb +4 -4
- data/lib/shrine/storage/s3.rb +62 -38
- data/lib/shrine/uploaded_file.rb +5 -1
- data/lib/shrine/version.rb +2 -2
- data/shrine.gemspec +6 -7
- metadata +23 -29
data/doc/metadata.md
CHANGED
@@ -15,6 +15,18 @@ uploaded_file.metadata #=>
|
|
15
15
|
# }
|
16
16
|
```
|
17
17
|
|
18
|
+
Under the hood, `Shrine#upload` calls `Shrine#extract_metadata`, which you can
|
19
|
+
also use directly to extract metadata from any IO object:
|
20
|
+
|
21
|
+
```rb
|
22
|
+
uploader.extract_metadata(io) #=>
|
23
|
+
# {
|
24
|
+
# "size" => 345993,
|
25
|
+
# "filename" => "matrix.mp4",
|
26
|
+
# "mime_type" => "video/mp4",
|
27
|
+
# }
|
28
|
+
```
|
29
|
+
|
18
30
|
The following metadata is extracted by default:
|
19
31
|
|
20
32
|
| Key | Default source |
|
@@ -23,7 +35,9 @@ The following metadata is extracted by default:
|
|
23
35
|
| `mime_type` | extracted from `io.content_type` |
|
24
36
|
| `size` | extracted from `io.size` |
|
25
37
|
|
26
|
-
|
38
|
+
## Accessing metadata
|
39
|
+
|
40
|
+
You can access the stored metadata in three ways:
|
27
41
|
|
28
42
|
```rb
|
29
43
|
# via methods (if they're defined)
|
@@ -42,17 +56,7 @@ uploaded_file["filename"]
|
|
42
56
|
uploaded_file["mime_type"]
|
43
57
|
```
|
44
58
|
|
45
|
-
|
46
|
-
also use directly to extract metadata from any IO object:
|
47
|
-
|
48
|
-
```rb
|
49
|
-
uploader.extract_metadata(io) #=>
|
50
|
-
# {
|
51
|
-
# "size" => 345993,
|
52
|
-
# "filename" => "matrix.mp4",
|
53
|
-
# "mime_type" => "video/mp4",
|
54
|
-
# }
|
55
|
-
```
|
59
|
+
## Controlling extraction
|
56
60
|
|
57
61
|
`Shrine#upload` accepts a `:metadata` option which accepts the following values:
|
58
62
|
|
@@ -85,11 +89,11 @@ By default, the `mime_type` metadata will be copied over from the
|
|
85
89
|
`#content_type` attribute of the input file (if present). However, since
|
86
90
|
`#content_type` value comes from the `Content-Type` header of the upload
|
87
91
|
request, it's *not guaranteed* to hold the actual MIME type of the file (browser
|
88
|
-
determines this header based on file extension).
|
89
|
-
|
90
|
-
`
|
91
|
-
|
92
|
-
|
92
|
+
determines this header based on file extension).
|
93
|
+
|
94
|
+
Moreover, only `ActionDispatch::Http::UploadedFile`, `Shrine::RackFile`, and
|
95
|
+
`Shrine::DataFile` objects have `#content_type` defined, so when uploading
|
96
|
+
objects such as `File`, the `mime_type` value will be nil by default.
|
93
97
|
|
94
98
|
To remedy that, Shrine comes with a
|
95
99
|
[`determine_mime_type`][determine_mime_type] plugin which is able to extract
|
@@ -112,15 +116,14 @@ You can choose different analyzers, and even mix-and-match them. See the
|
|
112
116
|
|
113
117
|
## Image Dimensions
|
114
118
|
|
115
|
-
Shrine comes with a `store_dimensions` plugin for
|
116
|
-
It adds `width` and `height` metadata values, and
|
117
|
-
`#height`, and `#dimensions` methods to the
|
118
|
-
|
119
|
-
have it use [MiniMagick] or [ruby-vips]:
|
119
|
+
Shrine comes with a [`store_dimensions`][store_dimensions] plugin for
|
120
|
+
extracting image dimensions. It adds `width` and `height` metadata values, and
|
121
|
+
also adds `#width`, `#height`, and `#dimensions` methods to the
|
122
|
+
`Shrine::UploadedFile` object.
|
120
123
|
|
121
124
|
```rb
|
122
125
|
# Gemfile
|
123
|
-
gem "fastimage"
|
126
|
+
gem "fastimage" # default analyzer
|
124
127
|
```
|
125
128
|
```rb
|
126
129
|
Shrine.plugin :store_dimensions
|
@@ -136,12 +139,17 @@ uploaded_file.height #=> 900
|
|
136
139
|
uploaded_file.dimensions #=> [1600, 900]
|
137
140
|
```
|
138
141
|
|
142
|
+
By default, the plugin uses [FastImage] to analyze dimensions, but you can also
|
143
|
+
have it use [MiniMagick] or [ruby-vips]. See the
|
144
|
+
[`store_dimensions`][store_dimensions] plugin docs for more details.
|
145
|
+
|
139
146
|
## Custom metadata
|
140
147
|
|
141
148
|
In addition to the built-in metadata, Shrine allows you to extract and store
|
142
|
-
any custom metadata, using the `add_metadata` plugin (which
|
143
|
-
`Shrine#extract_metadata`).
|
144
|
-
|
149
|
+
any custom metadata, using the [`add_metadata`][add_metadata] plugin (which
|
150
|
+
internally extends `Shrine#extract_metadata`).
|
151
|
+
|
152
|
+
For example, you might want to extract EXIF data from images:
|
145
153
|
|
146
154
|
```rb
|
147
155
|
# Gemfile
|
@@ -203,9 +211,20 @@ uploaded_file.metadata #=>
|
|
203
211
|
|
204
212
|
The yielded `io` object will not always be an object that responds to `#path`.
|
205
213
|
For example, with the `data_uri` plugin the `io` can be a `StringIO` wrapper,
|
206
|
-
with `restore_cached_data` or `refresh_metadata` plugins the `io` might
|
207
|
-
`Shrine::UploadedFile` object. So we're using `Shrine.with_file` to
|
208
|
-
have a file object.
|
214
|
+
while with `restore_cached_data` or `refresh_metadata` plugins the `io` might
|
215
|
+
be a `Shrine::UploadedFile` object. So, we're using `Shrine.with_file` to
|
216
|
+
ensure we have a file object.
|
217
|
+
|
218
|
+
### Adding metadata
|
219
|
+
|
220
|
+
If you wish to add metadata to an already attached file, you can do it as
|
221
|
+
follows:
|
222
|
+
|
223
|
+
```rb
|
224
|
+
photo.image_attacher.add_metadata("foo" => "bar")
|
225
|
+
photo.image.metadata #=> { ..., "foo" => "bar" }
|
226
|
+
photo.save # persist changes
|
227
|
+
```
|
209
228
|
|
210
229
|
## Metadata columns
|
211
230
|
|
@@ -225,15 +244,20 @@ photo.image_type #=> "image/jpeg"
|
|
225
244
|
When attaching files that were uploaded directly to the cloud or a [tus
|
226
245
|
server], Shrine won't automatically extract metadata from them, instead it will
|
227
246
|
copy any existing metadata that was set on the client side. The reason why this
|
228
|
-
is the default behaviour is because
|
229
|
-
|
230
|
-
|
231
|
-
|
247
|
+
is the default behaviour is because metadata extraction requires (at least
|
248
|
+
partially) retrieving file content from the storage, which could potentially be
|
249
|
+
expensive depending on the storage and the type of metadata being extracted.
|
250
|
+
|
251
|
+
```rb
|
252
|
+
# no additional metadata will be extracted in this assignment by default
|
253
|
+
photo.image = '{"id":"9e6581a4ea1.jpg","storage":"cache","metadata":{...}}'
|
254
|
+
```
|
232
255
|
|
233
|
-
|
234
|
-
|
235
|
-
you want to
|
236
|
-
|
256
|
+
### Extracting on attachment
|
257
|
+
|
258
|
+
If you want metadata to be automatically extracted on assignment (which is
|
259
|
+
useful if you want to validate the extracted metadata or have it immediately
|
260
|
+
available for any other reason), you can load the `restore_cached_data` plugin:
|
237
261
|
|
238
262
|
```rb
|
239
263
|
Shrine.plugin :restore_cached_data # automatically extract metadata from cached files on assignment
|
@@ -248,7 +272,9 @@ photo.image.metadata #=>
|
|
248
272
|
# }
|
249
273
|
```
|
250
274
|
|
251
|
-
###
|
275
|
+
### Extracting in the background
|
276
|
+
|
277
|
+
#### A) Extracting with promotion
|
252
278
|
|
253
279
|
If you're using [backgrounding], you can extract metadata during background
|
254
280
|
promotion using the `refresh_metadata` plugin (which the `restore_cached_data`
|
@@ -271,12 +297,14 @@ class PromoteJob
|
|
271
297
|
record = Object.const_get(record_class).find(record_id) # if using Active Record
|
272
298
|
|
273
299
|
attacher = attacher_class.retrieve(model: record, name: name, file: file_data)
|
274
|
-
attacher.refresh_metadata!
|
300
|
+
attacher.refresh_metadata! # extract metadata
|
275
301
|
attacher.atomic_promote
|
276
302
|
end
|
277
303
|
end
|
278
304
|
```
|
279
305
|
|
306
|
+
#### B) Extracting separately from promotion
|
307
|
+
|
280
308
|
You can also extract metadata in the background separately from promotion:
|
281
309
|
|
282
310
|
```rb
|
@@ -303,11 +331,13 @@ class MetadataJob
|
|
303
331
|
end
|
304
332
|
```
|
305
333
|
|
334
|
+
### Combining foreground and background
|
335
|
+
|
306
336
|
If you have some metadata that you want to extract in the foreground and some
|
307
337
|
that you want to extract in the background, you can use the uploader context:
|
308
338
|
|
309
339
|
```rb
|
310
|
-
class
|
340
|
+
class VideoUploader < Shrine
|
311
341
|
plugin :add_metadata
|
312
342
|
|
313
343
|
add_metadata do |io, **options|
|
@@ -324,7 +354,7 @@ class MyUploader < Shrine
|
|
324
354
|
end
|
325
355
|
```
|
326
356
|
```rb
|
327
|
-
class
|
357
|
+
class PromoteJob
|
328
358
|
include Sidekiq::Worker
|
329
359
|
|
330
360
|
def perform(attacher_class, record_class, record_id, name, file_data)
|
@@ -332,12 +362,16 @@ class MetadataJob
|
|
332
362
|
record = Object.const_get(record_class).find(record_id) # if using Active Record
|
333
363
|
|
334
364
|
attacher = attacher_class.retrieve(model: record, name: name, file: file_data)
|
335
|
-
attacher.refresh_metadata!(background: true)
|
336
|
-
attacher.
|
365
|
+
attacher.refresh_metadata!(background: true) # specify the flag
|
366
|
+
attacher.atomic_promote
|
337
367
|
end
|
338
368
|
end
|
339
369
|
```
|
340
370
|
|
371
|
+
Now triggering metadata extraction in the controller on attachment (using
|
372
|
+
`restore_cached_data` or `refresh_metadata` plugin) will skip the video
|
373
|
+
metadata block, which will be triggered later in the background job.
|
374
|
+
|
341
375
|
### Optimizations
|
342
376
|
|
343
377
|
If you want to do both metadata extraction and file processing during
|
@@ -389,4 +423,6 @@ end
|
|
389
423
|
[ruby-vips]: https://github.com/libvips/ruby-vips
|
390
424
|
[tus server]: https://github.com/janko/tus-ruby-server
|
391
425
|
[determine_mime_type]: https://shrinerb.com/docs/plugins/determine_mime_type
|
426
|
+
[store_dimensions]: https://shrinerb.com/docs/plugins/store_dimensions
|
427
|
+
[add_metadata]: https://shrinerb.com/docs/plugins/add_metadata
|
392
428
|
[backgrounding]: https://shrinerb.com/docs/plugins/backgrounding
|
data/doc/multiple_files.md
CHANGED
@@ -14,7 +14,7 @@ relationship with the main table, and files will be attached on the records in
|
|
14
14
|
the new table. That way each record from the main table can implicitly have
|
15
15
|
multiple attachments through the associated records.
|
16
16
|
|
17
|
-
```
|
17
|
+
```
|
18
18
|
album1
|
19
19
|
photo1
|
20
20
|
- attachment1
|
@@ -74,13 +74,15 @@ Sequel.migration do
|
|
74
74
|
change do
|
75
75
|
create_table :albums do
|
76
76
|
primary_key :id
|
77
|
-
|
77
|
+
|
78
|
+
String :title
|
78
79
|
end
|
79
80
|
|
80
81
|
create_table :photos do
|
81
82
|
primary_key :id
|
82
83
|
foreign_key :album_id, :albums
|
83
|
-
|
84
|
+
|
85
|
+
String :image_data
|
84
86
|
end
|
85
87
|
end
|
86
88
|
end
|
data/doc/paperclip.md
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
---
|
2
|
-
title:
|
2
|
+
title: Upgrading from Paperclip
|
3
3
|
---
|
4
4
|
|
5
5
|
This guide is aimed at helping Paperclip users transition to Shrine, and it
|
6
6
|
consists of three parts:
|
7
7
|
|
8
8
|
1. Explanation of the key differences in design between Paperclip and Shrine
|
9
|
-
2. Instructions how to migrate
|
9
|
+
2. Instructions how to migrate an existing app that uses Paperclip to Shrine
|
10
10
|
3. Extensive reference of Paperclip's interface with Shrine equivalents
|
11
11
|
|
12
12
|
## Overview
|
@@ -136,12 +136,12 @@ into separate columns.
|
|
136
136
|
While Paperclip works only with Active Record, Shrine is designed to integrate
|
137
137
|
with any persistence library (there are integrations for [Active
|
138
138
|
Record][activerecord], [Sequel][sequel], [ROM][rom], [Hanami][hanami] and
|
139
|
-
[
|
139
|
+
[Mongoid][mongoid]), and can also be used standalone:
|
140
140
|
|
141
141
|
```rb
|
142
142
|
attacher = ImageUploader::Attacher.new
|
143
143
|
attacher.attach File.open("nature.jpg")
|
144
|
-
attacher.file #=> #<Shrine::UploadedFile
|
144
|
+
attacher.file #=> #<Shrine::UploadedFile id="f4ba5bdbf366ef0b.jpg" ...>
|
145
145
|
attacher.url #=> "https://my-bucket.s3.amazonaws.com/f4ba5bdbf366ef0b.jpg"
|
146
146
|
attacher.data #=> { "id" => "f4ba5bdbf366ef0b.jpg", "storage" => "store", "metadata" => { ... } }
|
147
147
|
```
|
@@ -182,7 +182,7 @@ require "image_processing/mini_magick"
|
|
182
182
|
class ImageUploader < Shrine
|
183
183
|
plugin :derivatives
|
184
184
|
|
185
|
-
Attacher.
|
185
|
+
Attacher.derivatives do |original|
|
186
186
|
magick = ImageProcessing::MiniMagick.source(original)
|
187
187
|
|
188
188
|
{
|
@@ -206,15 +206,15 @@ uploaded processed files into the database (including any extracted metadata),
|
|
206
206
|
which then becomes the source of truth on which versions have been generated.
|
207
207
|
|
208
208
|
```rb
|
209
|
-
photo.image #=> #<Shrine::UploadedFile
|
209
|
+
photo.image #=> #<Shrine::UploadedFile id="original.jpg" ...>
|
210
210
|
photo.image_derivatives #=> {}
|
211
211
|
|
212
212
|
photo.image_derivatives! # triggers processing
|
213
213
|
photo.image_derivatives #=>
|
214
214
|
# {
|
215
|
-
# large: #<Shrine::UploadedFile
|
216
|
-
# medium: #<Shrine::UploadedFile
|
217
|
-
# small: #<Shrine::UploadedFile
|
215
|
+
# large: #<Shrine::UploadedFile id="large.jpg" metadata={"size"=>873232, ...} ...>,
|
216
|
+
# medium: #<Shrine::UploadedFile id="medium.jpg" metadata={"size"=>94823, ...} ...>,
|
217
|
+
# small: #<Shrine::UploadedFile id="small.jpg" metadata={"size"=>37322, ...} ...>,
|
218
218
|
# }
|
219
219
|
```
|
220
220
|
|
@@ -297,16 +297,21 @@ file.mime_type #=> "application/x-php"
|
|
297
297
|
## Migrating from Paperclip
|
298
298
|
|
299
299
|
You have an existing app using Paperclip and you want to transfer it to Shrine.
|
300
|
-
|
301
|
-
|
300
|
+
Let's assume we have a `Photo` model with the "image" attachment.
|
301
|
+
|
302
|
+
### 1. Add Shrine column
|
303
|
+
|
304
|
+
First we need to create the `image_data` column for Shrine:
|
302
305
|
|
303
306
|
```rb
|
304
307
|
add_column :photos, :image_data, :text
|
305
308
|
```
|
306
309
|
|
307
|
-
|
308
|
-
|
309
|
-
attachments
|
310
|
+
### 2. Dual write
|
311
|
+
|
312
|
+
Next, we need to make new Paperclip attachments write to the `image_data`
|
313
|
+
column. This can be done by including the below module to all models that have
|
314
|
+
Paperclip attachments:
|
310
315
|
|
311
316
|
```rb
|
312
317
|
require "shrine"
|
@@ -318,8 +323,7 @@ Shrine.storages = {
|
|
318
323
|
|
319
324
|
Shrine.plugin :model
|
320
325
|
Shrine.plugin :derivatives
|
321
|
-
|
322
|
-
```rb
|
326
|
+
|
323
327
|
module PaperclipShrineSynchronization
|
324
328
|
def self.included(model)
|
325
329
|
model.before_save do
|
@@ -336,8 +340,8 @@ module PaperclipShrineSynchronization
|
|
336
340
|
if attachment.size.present?
|
337
341
|
attacher.set shrine_file(attachment)
|
338
342
|
|
339
|
-
attachment.styles.each do |
|
340
|
-
attacher.merge_derivatives(
|
343
|
+
attachment.styles.each do |style_name, style|
|
344
|
+
attacher.merge_derivatives(style_name => shrine_file(style))
|
341
345
|
end
|
342
346
|
else
|
343
347
|
attacher.set nil
|
@@ -372,7 +376,7 @@ module PaperclipShrineSynchronization
|
|
372
376
|
# If you'll be using a `:prefix` on your Shrine storage, or you're storing
|
373
377
|
# files on the filesystem, make sure to subtract the appropriate part
|
374
378
|
# from the path assigned to `:id`.
|
375
|
-
def
|
379
|
+
def shrine_style_file(style)
|
376
380
|
Shrine.uploaded_file(
|
377
381
|
storage: :store,
|
378
382
|
id: style.attachment.path(style.name),
|
@@ -389,34 +393,35 @@ end
|
|
389
393
|
```
|
390
394
|
|
391
395
|
After you deploy this code, the `image_data` column should now be successfully
|
392
|
-
synchronized with new attachments.
|
393
|
-
|
396
|
+
synchronized with new attachments.
|
397
|
+
|
398
|
+
### 3. Data migration
|
399
|
+
|
400
|
+
Next step is to run a script which writes all existing Paperclip attachments to
|
401
|
+
`image_data`:
|
394
402
|
|
395
403
|
```rb
|
396
404
|
Photo.find_each do |photo|
|
397
|
-
|
398
|
-
photo.write_shrine_data(name) if klass == Photo
|
399
|
-
end
|
405
|
+
photo.write_shrine_data(:image)
|
400
406
|
photo.save!
|
401
407
|
end
|
402
408
|
```
|
403
409
|
|
410
|
+
### 4. Rewrite code
|
411
|
+
|
404
412
|
Now you should be able to rewrite your application so that it uses Shrine
|
405
|
-
instead of Paperclip
|
406
|
-
|
407
|
-
below.
|
413
|
+
instead of Paperclip (you can consult the reference in the next section). You
|
414
|
+
can remove the `PaperclipShrineSynchronization` module as well.
|
408
415
|
|
409
|
-
|
410
|
-
(specifically versions). You can run a script that will fill in any missing
|
411
|
-
metadata defined in your Shrine uploader:
|
416
|
+
### 5. Remove Paperclip columns
|
412
417
|
|
413
|
-
|
414
|
-
Shrine.plugin :refresh_metadata
|
418
|
+
If everything is looking good, we can remove Paperclip columns:
|
415
419
|
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
+
```rb
|
421
|
+
remove_column :photos, :image_file_name
|
422
|
+
remove_column :photos, :image_file_size
|
423
|
+
remove_column :photos, :image_content_type
|
424
|
+
remove_column :photos, :image_updated_at
|
420
425
|
```
|
421
426
|
|
422
427
|
## Paperclip to Shrine direct mapping
|
@@ -457,8 +462,8 @@ Processing is defined by using the `derivatives` plugin:
|
|
457
462
|
class ImageUploader < Shrine
|
458
463
|
plugin :derivatives
|
459
464
|
|
460
|
-
Attacher.
|
461
|
-
magick = ImageProcessing::MiniMagick.source(
|
465
|
+
Attacher.derivatives do |original|
|
466
|
+
magick = ImageProcessing::MiniMagick.source(original)
|
462
467
|
|
463
468
|
{
|
464
469
|
large: magick.resize_to_limit!(800, 800),
|
@@ -477,8 +482,8 @@ For default URLs you can use the `default_url` plugin:
|
|
477
482
|
class ImageUploader < Shrine
|
478
483
|
plugin :default_url
|
479
484
|
|
480
|
-
Attacher.default_url do |
|
481
|
-
"/
|
485
|
+
Attacher.default_url do |derivative: nil, **|
|
486
|
+
"/images/placeholders/#{derivative || "original"}.jpg"
|
482
487
|
end
|
483
488
|
end
|
484
489
|
```
|
@@ -506,16 +511,79 @@ Alternatively, if you want to generate locations yourself you can override the
|
|
506
511
|
|
507
512
|
```rb
|
508
513
|
class ImageUploader < Shrine
|
509
|
-
def generate_location(io, **
|
510
|
-
|
514
|
+
def generate_location(io, record: nil, name: nil, **)
|
515
|
+
[ storage_key,
|
516
|
+
record && record.class.name.underscore,
|
517
|
+
record && record.id,
|
518
|
+
super,
|
519
|
+
io.original_filename ].compact.join("/")
|
511
520
|
end
|
512
521
|
end
|
513
522
|
```
|
523
|
+
```
|
524
|
+
cache/user/123/2feff8c724e7ce17/nature.jpg
|
525
|
+
store/user/456/7f99669fde1e01fc/kitten.jpg
|
526
|
+
...
|
527
|
+
```
|
514
528
|
|
515
529
|
#### `:validate_media_type`
|
516
530
|
|
517
531
|
Shrine has this functionality in the `determine_mime_type` plugin.
|
518
532
|
|
533
|
+
### `validates_attachment`
|
534
|
+
|
535
|
+
#### `:presence`
|
536
|
+
|
537
|
+
For presence validation you can use your ORM's presence validator:
|
538
|
+
|
539
|
+
```rb
|
540
|
+
class Photo < ActiveRecord::Base
|
541
|
+
include ImageUploader::Attachment(:image)
|
542
|
+
validates_presence_of :image
|
543
|
+
end
|
544
|
+
```
|
545
|
+
|
546
|
+
#### `:content_type`
|
547
|
+
|
548
|
+
You can do MIME type validation with Shrine's `validation_helpers` plugin:
|
549
|
+
|
550
|
+
```rb
|
551
|
+
class ImageUploader < Shrine
|
552
|
+
plugin :validation_helpers
|
553
|
+
|
554
|
+
Attacher.validate do
|
555
|
+
validate_mime_type %w[image/jpeg image/png image/webp]
|
556
|
+
end
|
557
|
+
end
|
558
|
+
```
|
559
|
+
|
560
|
+
Make sure to also load the `determine_mime_type` plugin to detect MIME type
|
561
|
+
from file content.
|
562
|
+
|
563
|
+
```rb
|
564
|
+
# Gemfile
|
565
|
+
gem "mimemagic"
|
566
|
+
```
|
567
|
+
```rb
|
568
|
+
Shrine.plugin :determine_mime_type, analyzer: -> (io, analyzers) do
|
569
|
+
analyzers[:mimemagic].call(io) || analyzers[:file].call(io)
|
570
|
+
end
|
571
|
+
```
|
572
|
+
|
573
|
+
#### `:size`
|
574
|
+
|
575
|
+
You can do filesize validation with Shrine's `validation_helpers` plugin:
|
576
|
+
|
577
|
+
```rb
|
578
|
+
class ImageUploader < Shrine
|
579
|
+
plugin :validation_helpers
|
580
|
+
|
581
|
+
Attacher.validate do
|
582
|
+
validate_max_size 10*1024*1024
|
583
|
+
end
|
584
|
+
end
|
585
|
+
```
|
586
|
+
|
519
587
|
### `Paperclip::Attachment`
|
520
588
|
|
521
589
|
This section explains the equivalent of Paperclip attachment's methods, in
|