shrine 3.0.1 → 3.1.0
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 +16 -0
- data/LICENSE.txt +1 -1
- data/README.md +7 -2
- data/doc/advantages.md +29 -12
- data/doc/carrierwave.md +54 -22
- data/doc/changing_derivatives.md +39 -39
- data/doc/getting_started.md +63 -58
- data/doc/multiple_files.md +5 -3
- data/doc/paperclip.md +92 -33
- data/doc/plugins/activerecord.md +1 -1
- data/doc/plugins/data_uri.md +2 -2
- data/doc/plugins/derivation_endpoint.md +26 -28
- data/doc/plugins/derivatives.md +170 -142
- data/doc/plugins/determine_mime_type.md +2 -2
- 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/persistence.md +1 -0
- data/doc/plugins/refresh_metadata.md +5 -4
- data/doc/plugins/remote_url.md +2 -2
- data/doc/plugins/signature.md +11 -2
- data/doc/plugins/store_dimensions.md +2 -2
- data/doc/plugins/upload_endpoint.md +7 -11
- data/doc/plugins/validation_helpers.md +3 -3
- data/doc/processing.md +5 -5
- data/doc/refile.md +30 -9
- data/doc/release_notes/2.19.0.md +1 -1
- data/doc/release_notes/3.0.1.md +4 -0
- data/doc/release_notes/3.1.0.md +73 -0
- data/doc/securing_uploads.md +1 -1
- data/doc/storage/file_system.md +1 -1
- data/doc/storage/s3.md +1 -5
- data/doc/upgrading_to_3.md +4 -2
- data/doc/validation.md +3 -2
- data/lib/shrine.rb +1 -2
- data/lib/shrine/attacher.rb +4 -4
- data/lib/shrine/attachment.rb +3 -3
- data/lib/shrine/plugins/add_metadata.rb +1 -5
- data/lib/shrine/plugins/default_storage.rb +6 -6
- data/lib/shrine/plugins/derivatives.rb +4 -3
- data/lib/shrine/plugins/signature.rb +7 -6
- data/lib/shrine/plugins/store_dimensions.rb +18 -9
- data/lib/shrine/uploaded_file.rb +0 -1
- data/lib/shrine/version.rb +2 -2
- metadata +3 -2
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
@@ -6,7 +6,7 @@ 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
|
@@ -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
|
{
|
@@ -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
|
```
|
@@ -516,6 +521,60 @@ end
|
|
516
521
|
|
517
522
|
Shrine has this functionality in the `determine_mime_type` plugin.
|
518
523
|
|
524
|
+
### `validates_attachment`
|
525
|
+
|
526
|
+
#### `:presence`
|
527
|
+
|
528
|
+
For presence validation you can use your ORM's presence validator:
|
529
|
+
|
530
|
+
```rb
|
531
|
+
class Photo < ActiveRecord::Base
|
532
|
+
include ImageUploader::Attachment(:image)
|
533
|
+
validates_presence_of :image
|
534
|
+
end
|
535
|
+
```
|
536
|
+
|
537
|
+
#### `:content_type`
|
538
|
+
|
539
|
+
You can do MIME type validation with Shrine's `validation_helpers` plugin:
|
540
|
+
|
541
|
+
```rb
|
542
|
+
class ImageUploader < Shrine
|
543
|
+
plugin :validation_helpers
|
544
|
+
|
545
|
+
Attacher.validate do
|
546
|
+
validate_mime_type %w[image/jpeg image/png image/webp]
|
547
|
+
end
|
548
|
+
end
|
549
|
+
```
|
550
|
+
|
551
|
+
Make sure to also load the `determine_mime_type` plugin to detect MIME type
|
552
|
+
from file content.
|
553
|
+
|
554
|
+
```rb
|
555
|
+
# Gemfile
|
556
|
+
gem "mimemagic"
|
557
|
+
```
|
558
|
+
```rb
|
559
|
+
Shrine.plugin :determine_mime_type, analyzer: -> (io, analyzers) do
|
560
|
+
analyzers[:mimemagic].call(io) || analyzers[:file].call(io)
|
561
|
+
end
|
562
|
+
```
|
563
|
+
|
564
|
+
#### `:size`
|
565
|
+
|
566
|
+
You can do filesize validation with Shrine's `validation_helpers` plugin:
|
567
|
+
|
568
|
+
```rb
|
569
|
+
class ImageUploader < Shrine
|
570
|
+
plugin :validation_helpers
|
571
|
+
|
572
|
+
Attacher.validate do
|
573
|
+
validate_max_size 10*1024*1024
|
574
|
+
end
|
575
|
+
end
|
576
|
+
```
|
577
|
+
|
519
578
|
### `Paperclip::Attachment`
|
520
579
|
|
521
580
|
This section explains the equivalent of Paperclip attachment's methods, in
|
data/doc/plugins/activerecord.md
CHANGED
data/doc/plugins/data_uri.md
CHANGED
@@ -123,7 +123,7 @@ payload:
|
|
123
123
|
|
124
124
|
A default log subscriber is added as well which logs these events:
|
125
125
|
|
126
|
-
```
|
126
|
+
```
|
127
127
|
Data URI (5ms) – {:uploader=>Shrine}
|
128
128
|
```
|
129
129
|
|
@@ -134,7 +134,7 @@ plugin :data_uri, log_subscriber: -> (event) {
|
|
134
134
|
Shrine.logger.info JSON.generate(name: event.name, duration: event.duration, uploader: event[:uploader])
|
135
135
|
}
|
136
136
|
```
|
137
|
-
```
|
137
|
+
```
|
138
138
|
{"name":"data_uri","duration":5,"uploader":"Shrine"}
|
139
139
|
```
|
140
140
|
|
@@ -68,7 +68,7 @@ generates an URL consisting of the configured [path prefix](#prefix),
|
|
68
68
|
derivation name and arguments, serialized uploaded file, and an URL signature
|
69
69
|
generated using the configured secret key:
|
70
70
|
|
71
|
-
```
|
71
|
+
```
|
72
72
|
/ derivations/image / thumbnail / 600/400 / eyJmZvbyIb3JhZ2UiOiJzdG9yZSJ9 ? signature=...
|
73
73
|
└──── prefix ─────┘ └── name ──┘ └─ args ─┘ └─── serialized source file ───┘
|
74
74
|
```
|
@@ -197,7 +197,8 @@ Rails.application.routes.draw do
|
|
197
197
|
end
|
198
198
|
end
|
199
199
|
end
|
200
|
-
|
200
|
+
```
|
201
|
+
```rb
|
201
202
|
# app/controllers/photos_controller.rb
|
202
203
|
class PhotosController < ApplicationController
|
203
204
|
def thumbnail
|
@@ -483,32 +484,27 @@ such as AWS S3 or Google Cloud Storage.
|
|
483
484
|
### Deleting derivatives
|
484
485
|
|
485
486
|
When the original attachment is deleted, its uploaded derivatives will not be
|
486
|
-
automatically deleted, you will need to do the deletion manually.
|
487
|
-
|
488
|
-
`Attacher#destroy`.
|
487
|
+
automatically deleted, you will need to do the deletion manually. If you're
|
488
|
+
using [backgrounding], you can do this in your `DestroyJob`.
|
489
489
|
|
490
|
-
|
490
|
+
If your storage implements `#delete_prefixed`, and you're using the default
|
491
|
+
[`:upload_location`](#upload-location), you can delete the directory containing
|
492
|
+
derivatives:
|
491
493
|
|
492
494
|
```rb
|
493
|
-
class
|
494
|
-
|
495
|
-
|
496
|
-
super
|
495
|
+
class DestroyJob < ActiveJob::Base
|
496
|
+
def perform(attacher_class, data)
|
497
|
+
# ... destroy attached file ...
|
497
498
|
|
498
|
-
|
499
|
-
|
499
|
+
derivatives_directory = attacher.file.id + "/"
|
500
|
+
storage = attacher.store.storage
|
500
501
|
|
501
|
-
|
502
|
-
end
|
502
|
+
storage.delete_prefixed(derivatives_directory)
|
503
503
|
end
|
504
504
|
end
|
505
505
|
```
|
506
506
|
|
507
|
-
|
508
|
-
and that you're using default [`:upload_location`](#upload-location).
|
509
|
-
|
510
|
-
Alternatively, you can delete each derivative individually using
|
511
|
-
`Derivation#delete`:
|
507
|
+
Alternatively, you can delete each derivative individually:
|
512
508
|
|
513
509
|
```rb
|
514
510
|
class ImageUploader < Shrine
|
@@ -518,14 +514,15 @@ class ImageUploader < Shrine
|
|
518
514
|
[:thumbnail, 400, 300],
|
519
515
|
...
|
520
516
|
]
|
517
|
+
end
|
518
|
+
```
|
519
|
+
```rb
|
520
|
+
class DestroyJob < ActiveJob::Base
|
521
|
+
def perform(attacher_class, data)
|
522
|
+
# ... destroy attached file ...
|
521
523
|
|
522
|
-
|
523
|
-
|
524
|
-
super
|
525
|
-
|
526
|
-
DERIVATIONS.each do |args|
|
527
|
-
file.derivation(*args).delete
|
528
|
-
end
|
524
|
+
attacher.shrine_class::DERIVATIONS.each do |args|
|
525
|
+
attacher.file.derivation(*args).delete
|
529
526
|
end
|
530
527
|
end
|
531
528
|
end
|
@@ -830,7 +827,7 @@ following payload:
|
|
830
827
|
|
831
828
|
A default log subscriber is added as well which logs these events:
|
832
829
|
|
833
|
-
```
|
830
|
+
```
|
834
831
|
Derivation (492ms) – {:name=>:thumbnail, :args=>[600, 600], :uploader=>Shrine}
|
835
832
|
```
|
836
833
|
|
@@ -846,7 +843,7 @@ plugin :derivation_endpoint, log_subscriber: -> (event) {
|
|
846
843
|
)
|
847
844
|
}
|
848
845
|
```
|
849
|
-
```
|
846
|
+
```
|
850
847
|
{"name":"derivation","duration":492,"name":"thumbnail","args":[600,600],"uploader":"Shrine"}
|
851
848
|
```
|
852
849
|
|
@@ -861,3 +858,4 @@ plugin :derivation_endpoint, log_subscriber: nil
|
|
861
858
|
[`Content-Type`]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type
|
862
859
|
[`Content-Disposition`]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition
|
863
860
|
[`Cache-Control`]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control
|
861
|
+
[backgrounding]: https://shrinerb.com/docs/plugins/backgrounding
|
data/doc/plugins/derivatives.md
CHANGED
@@ -10,12 +10,11 @@ main attachment data in the same record attribute.
|
|
10
10
|
Shrine.plugin :derivatives
|
11
11
|
```
|
12
12
|
|
13
|
-
##
|
13
|
+
## Quick start
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
to create derivatives.
|
15
|
+
You'll usually want to create derivatives from an attached file. The simplest
|
16
|
+
way to do this is to define a processor which returns the processed files, and
|
17
|
+
then trigger it when you want to create derivatives.
|
19
18
|
|
20
19
|
Here is an example of generating image thumbnails:
|
21
20
|
|
@@ -27,7 +26,7 @@ gem "image_processing", "~> 1.8"
|
|
27
26
|
require "image_processing/mini_magick"
|
28
27
|
|
29
28
|
class ImageUploader < Shrine
|
30
|
-
Attacher.
|
29
|
+
Attacher.derivatives do |original|
|
31
30
|
magick = ImageProcessing::MiniMagick.source(original)
|
32
31
|
|
33
32
|
{
|
@@ -56,8 +55,17 @@ route make sure to create derivatives for new attachments:
|
|
56
55
|
photo.image_derivatives! if photo.image_changed?
|
57
56
|
```
|
58
57
|
|
59
|
-
|
60
|
-
|
58
|
+
You can then retrieve created derivatives as follows:
|
59
|
+
|
60
|
+
```rb
|
61
|
+
photo.image(:large) #=> #<Shrine::UploadedFile ...>
|
62
|
+
photo.image(:large).url #=> "https://s3.amazonaws.com/path/to/large.jpg"
|
63
|
+
photo.image(:large).size #=> 43843
|
64
|
+
photo.image(:large).mime_type #=> "image/jpeg"
|
65
|
+
```
|
66
|
+
|
67
|
+
The derivatives data is stored in the `#<name>_data` record attribute, alongside
|
68
|
+
the main file data:
|
61
69
|
|
62
70
|
```rb
|
63
71
|
photo.image_data #=>
|
@@ -73,22 +81,112 @@ photo.image_data #=>
|
|
73
81
|
# }
|
74
82
|
```
|
75
83
|
|
76
|
-
|
84
|
+
## Retrieving derivatives
|
85
|
+
|
86
|
+
The list of stored derivatives can be retrieved with `#<name>_derivatives`:
|
77
87
|
|
78
88
|
```rb
|
79
|
-
photo.
|
80
|
-
|
81
|
-
|
82
|
-
|
89
|
+
photo.image_derivatives #=>
|
90
|
+
# {
|
91
|
+
# small: #<Shrine::UploadedFile ...>,
|
92
|
+
# medium: #<Shrine::UploadedFile ...>,
|
93
|
+
# large: #<Shrine::UploadedFile ...>,
|
94
|
+
# }
|
95
|
+
```
|
96
|
+
|
97
|
+
A specific derivative can be retrieved in any of the following ways:
|
98
|
+
|
99
|
+
```rb
|
100
|
+
photo.image_derivatives[:small] #=> #<Shrine::UploadedFile ...>
|
101
|
+
photo.image_derivatives(:small) #=> #<Shrine::UploadedFile ...>
|
102
|
+
photo.image(:small) #=> #<Shrine::UploadedFile ...>
|
103
|
+
```
|
104
|
+
|
105
|
+
Or with nested derivatives:
|
106
|
+
|
107
|
+
```rb
|
108
|
+
photo.image_derivatives #=> { thumbnail: { small: ..., medium: ..., large: ... } }
|
109
|
+
|
110
|
+
photo.image_derivatives.dig(:thumbnail, :small) #=> #<Shrine::UploadedFile ...>
|
111
|
+
photo.image_derivatives(:thumbnail, :small) #=> #<Shrine::UploadedFile ...>
|
112
|
+
photo.image(:thumbnails, :small) #=> #<Shrine::UploadedFile ...>
|
113
|
+
```
|
114
|
+
|
115
|
+
### Derivative URL
|
116
|
+
|
117
|
+
You can retrieve the URL of a derivative URL with `#<name>_url`:
|
118
|
+
|
119
|
+
```rb
|
120
|
+
photo.image_url(:small) #=> "https://example.com/small.jpg"
|
121
|
+
photo.image_url(:medium) #=> "https://example.com/medium.jpg"
|
122
|
+
photo.image_url(:large) #=> "https://example.com/large.jpg"
|
123
|
+
```
|
124
|
+
|
125
|
+
For nested derivatives you can pass multiple keys:
|
126
|
+
|
127
|
+
```rb
|
128
|
+
photo.image_derivatives #=> { thumbnail: { small: ..., medium: ..., large: ... } }
|
129
|
+
|
130
|
+
photo.image_url(:thumbnail, :medium) #=> "https://example.com/medium.jpg"
|
131
|
+
```
|
132
|
+
|
133
|
+
By default, `#<name>_url` method will return `nil` if derivative is not found.
|
134
|
+
You can use the [`default_url`][default_url] plugin to set up URL fallbacks:
|
135
|
+
|
136
|
+
```rb
|
137
|
+
Attacher.default_url do |derivative: nil, **|
|
138
|
+
"https://my-app.com/fallbacks/#{derivative}.jpg" if derivative
|
139
|
+
end
|
140
|
+
```
|
141
|
+
```rb
|
142
|
+
photo.image_url(:medium) #=> "https://example.com/fallbacks.com/medium.jpg"
|
83
143
|
```
|
84
144
|
|
85
|
-
|
86
|
-
|
87
|
-
|
145
|
+
Any additional URL options passed to `#<name>_url` will be forwarded to the
|
146
|
+
storage:
|
147
|
+
|
148
|
+
```rb
|
149
|
+
photo.image_url(:small, response_content_disposition: "attachment")
|
150
|
+
```
|
151
|
+
|
152
|
+
You can also retrieve the derivative URL via `UploadedFile#url`:
|
153
|
+
|
154
|
+
```rb
|
155
|
+
photo.image_derivatives[:large].url
|
156
|
+
```
|
157
|
+
|
158
|
+
## Attacher API
|
159
|
+
|
160
|
+
The derivatives API is primarily defined on the `Shrine::Attacher` class, with
|
161
|
+
some important methods also being exposed through the `Shrine::Attachment`
|
162
|
+
module.
|
163
|
+
|
164
|
+
Here is a model example with equivalent attacher code:
|
165
|
+
|
166
|
+
```rb
|
167
|
+
photo.image_derivatives!(:thumbnails)
|
168
|
+
photo.image_derivatives #=> { ... }
|
169
|
+
|
170
|
+
photo.image_url(:large) #=> "https://..."
|
171
|
+
photo.image(:large) #=> #<Shrine::UploadedFile ...>
|
172
|
+
```
|
173
|
+
```rb
|
174
|
+
attacher.create_derivatives(:thumbnails)
|
175
|
+
attacher.get_derivatives #=> { ... }
|
176
|
+
|
177
|
+
attacher.url(:large) #=> "https://..."
|
178
|
+
attacher.get(:large) #=> "#<Shrine::UploadedFile>"
|
179
|
+
```
|
180
|
+
|
181
|
+
## Creating derivatives
|
182
|
+
|
183
|
+
By default, the `Attacher#create_derivatives` method downloads the attached
|
184
|
+
file, calls the processor, uploads results to attacher's permanent storage, and
|
185
|
+
saves uploaded files on the attacher.
|
88
186
|
|
89
187
|
```rb
|
90
188
|
attacher.file #=> #<Shrine::UploadedFile id="original.jpg" storage=:store ...>
|
91
|
-
attacher.create_derivatives # calls
|
189
|
+
attacher.create_derivatives # calls default processor and uploads results
|
92
190
|
attacher.derivatives #=>
|
93
191
|
# {
|
94
192
|
# small: #<Shrine::UploadedFile id="small.jpg" storage=:store ...>,
|
@@ -97,9 +195,7 @@ attacher.derivatives #=>
|
|
97
195
|
# }
|
98
196
|
```
|
99
197
|
|
100
|
-
|
101
|
-
file, calls the processor, uploads results to attacher's permanent storage, and
|
102
|
-
saves uploaded files on the attacher. Any additional arguments are forwarded to
|
198
|
+
Any additional arguments are forwarded to
|
103
199
|
[`Attacher#process_derivatives`](#processing-derivatives):
|
104
200
|
|
105
201
|
```rb
|
@@ -110,32 +206,43 @@ attacher.create_derivatives(foo: "bar") # pass custom options to the proce
|
|
110
206
|
### Naming processors
|
111
207
|
|
112
208
|
If you want to have multiple processors for an uploader, you can assign each
|
113
|
-
processor a name
|
114
|
-
the desired processor.
|
209
|
+
processor a name:
|
115
210
|
|
116
211
|
```rb
|
117
212
|
class ImageUploader < Shrine
|
118
|
-
Attacher.
|
119
|
-
|
213
|
+
Attacher.derivatives :thumbnails do |original|
|
214
|
+
{ large: ..., medium: ..., small: ... }
|
120
215
|
end
|
121
216
|
|
122
|
-
Attacher.
|
123
|
-
|
217
|
+
Attacher.derivatives :crop do |original|
|
218
|
+
{ cropped: ... }
|
124
219
|
end
|
125
|
-
|
126
|
-
# ...
|
127
220
|
end
|
128
221
|
```
|
222
|
+
|
223
|
+
Then when creating derivatives you can specify the name of the desired
|
224
|
+
processor. New derivatives will be merged with any existing ones.
|
225
|
+
|
129
226
|
```rb
|
130
|
-
photo.image_derivatives!(:thumbnails)
|
131
|
-
# or
|
132
227
|
attacher.create_derivatives(:thumbnails)
|
228
|
+
attacher.derivatives #=> { large: ..., medium: ..., small: ... }
|
229
|
+
|
230
|
+
attacher.create_derivatives(:crop)
|
231
|
+
attacher.derivatives #=> { large: ..., medium: ..., small: ..., cropped: ... }
|
133
232
|
```
|
134
233
|
|
135
234
|
### Derivatives storage
|
136
235
|
|
137
236
|
By default, derivatives are uploaded to the permanent storage of the attacher.
|
138
|
-
You can change the
|
237
|
+
You can change the destination storage by passing `:storage` to the creation
|
238
|
+
call:
|
239
|
+
|
240
|
+
```rb
|
241
|
+
attacher.create_derivatives(storage: :cache) # will be promoted together with main file
|
242
|
+
attacher.create_derivatives(storage: :other_store)
|
243
|
+
```
|
244
|
+
|
245
|
+
You can also change the default destination storage with the `:storage` plugin
|
139
246
|
option:
|
140
247
|
|
141
248
|
```rb
|
@@ -186,7 +293,7 @@ Derivatives can be nested to any level, using both hashes and arrays, but the
|
|
186
293
|
top-level object must be a hash.
|
187
294
|
|
188
295
|
```rb
|
189
|
-
Attacher.
|
296
|
+
Attacher.derivatives :tiff do |original|
|
190
297
|
{
|
191
298
|
thumbnail: {
|
192
299
|
small: small,
|
@@ -201,114 +308,29 @@ Attacher.derivatives_processor :tiff do |original|
|
|
201
308
|
}
|
202
309
|
end
|
203
310
|
```
|
204
|
-
|
205
|
-
## Retrieving derivatives
|
206
|
-
|
207
|
-
If you're using the `Shrine::Attachment` module, you can retrieve stored
|
208
|
-
derivatives by calling `#<name>_derivatives` on your model/entity.
|
209
|
-
|
210
|
-
```rb
|
211
|
-
class Photo < Model(:image_data)
|
212
|
-
include ImageUploader::Attachment(:image)
|
213
|
-
end
|
214
|
-
```
|
215
|
-
```rb
|
216
|
-
photo.image_derivatives #=>
|
217
|
-
# {
|
218
|
-
# small: #<Shrine::UploadedFile>,
|
219
|
-
# medium: #<Shrine::UploadedFile>,
|
220
|
-
# large: #<Shrine::UploadedFile>,
|
221
|
-
# }
|
222
|
-
```
|
223
|
-
|
224
|
-
A specific derivative can be retrieved in any of the following ways:
|
225
|
-
|
226
|
-
```rb
|
227
|
-
photo.image_derivatives[:small] #=> #<Shrine::UploadedFile>
|
228
|
-
photo.image_derivatives(:small) #=> #<Shrine::UploadedFile>
|
229
|
-
photo.image(:small) #=> #<Shrine::UploadedFile>
|
230
|
-
```
|
231
|
-
|
232
|
-
And with nested derivatives:
|
233
|
-
|
234
|
-
```rb
|
235
|
-
photo.image_derivatives #=> { thumbnail: { small: ..., medium: ..., large: ... } }
|
236
|
-
|
237
|
-
photo.image_derivatives.dig(:thumbnail, :small) #=> #<Shrine::UploadedFile>
|
238
|
-
photo.image_derivatives(:thumbnail, :small) #=> #<Shrine::UploadedFile>
|
239
|
-
photo.image(:thumbnails, :small) #=> #<Shrine::UploadedFile>
|
240
|
-
```
|
241
|
-
|
242
|
-
When using `Shrine::Attacher` directly, you can retrieve derivatives using
|
243
|
-
`Attacher#derivatives`:
|
244
|
-
|
245
311
|
```rb
|
246
312
|
attacher.derivatives #=>
|
247
313
|
# {
|
248
|
-
#
|
249
|
-
#
|
250
|
-
#
|
314
|
+
# thumbnail: {
|
315
|
+
# small: #<Shrine::UploadedFile ...>,
|
316
|
+
# medium: #<Shrine::UploadedFile ...>,
|
317
|
+
# large: #<Shrine::UploadedFile ...>,
|
318
|
+
# },
|
319
|
+
# layers: [
|
320
|
+
# #<Shrine::UploadedFile ...>,
|
321
|
+
# #<Shrine::UploadedFile ...>,
|
322
|
+
# # ...
|
323
|
+
# ]
|
251
324
|
# }
|
252
325
|
```
|
253
326
|
|
254
|
-
## Derivative URL
|
255
|
-
|
256
|
-
If you're using the `Shrine::Attachment` module, you can use the `#<name>_url`
|
257
|
-
method to retrieve the URL of a derivative.
|
258
|
-
|
259
|
-
```rb
|
260
|
-
class Photo < Model(:image_data)
|
261
|
-
include ImageUploader::Attachment(:image)
|
262
|
-
end
|
263
|
-
```
|
264
|
-
```rb
|
265
|
-
photo.image_url(:small) #=> "https://example.com/small.jpg"
|
266
|
-
photo.image_url(:medium) #=> "https://example.com/medium.jpg"
|
267
|
-
photo.image_url(:large) #=> "https://example.com/large.jpg"
|
268
|
-
```
|
269
|
-
|
270
|
-
For nested derivatives you can pass multiple keys:
|
271
|
-
|
272
|
-
```rb
|
273
|
-
photo.image_derivatives #=> { thumbnail: { small: ..., medium: ..., large: ... } }
|
274
|
-
|
275
|
-
photo.image_url(:thumbnail, :medium) #=> "https://example.com/medium.jpg"
|
276
|
-
```
|
277
|
-
|
278
|
-
By default, `#<name>_url` method will return `nil` if derivative is not found.
|
279
|
-
You can use the [`default_url`][default_url] plugin to set up URL fallbacks:
|
280
|
-
|
281
|
-
```rb
|
282
|
-
Attacher.default_url do |derivative: nil, **|
|
283
|
-
"https://my-app.com/fallbacks/#{derivative}.jpg" if derivative
|
284
|
-
end
|
285
|
-
```
|
286
|
-
```rb
|
287
|
-
photo.image_url(:medium) #=> "https://example.com/fallbacks.com/medium.jpg"
|
288
|
-
```
|
289
|
-
|
290
|
-
Any additional URL options passed to `#<name>_url` will be forwarded to the
|
291
|
-
storage:
|
292
|
-
|
293
|
-
```rb
|
294
|
-
photo.image_url(:small, response_content_disposition: "attachment")
|
295
|
-
```
|
296
|
-
|
297
|
-
You can also retrieve the derivative URL via `UploadedFile#url`:
|
298
|
-
|
299
|
-
```rb
|
300
|
-
photo.image_derivatives[:large].url
|
301
|
-
# or
|
302
|
-
attacher.derivatives[:large].url
|
303
|
-
```
|
304
|
-
|
305
327
|
## Processing derivatives
|
306
328
|
|
307
329
|
A derivatives processor block takes the original file, and is expected to
|
308
330
|
return a hash of processed files (it can be [nested](#nesting-derivatives)).
|
309
331
|
|
310
332
|
```rb
|
311
|
-
Attacher.
|
333
|
+
Attacher.derivatives :my_processor do |original|
|
312
334
|
# return a hash of processed files
|
313
335
|
end
|
314
336
|
```
|
@@ -327,7 +349,7 @@ The processor block is evaluated in context of the `Shrine::Attacher` instance,
|
|
327
349
|
which allows you to change your processing logic based on the record data.
|
328
350
|
|
329
351
|
```rb
|
330
|
-
Attacher.
|
352
|
+
Attacher.derivatives :my_processor do |original|
|
331
353
|
self #=> #<Shrine::Attacher>
|
332
354
|
|
333
355
|
record #=> #<Photo>
|
@@ -345,7 +367,7 @@ forwarded to the processor:
|
|
345
367
|
attacher.process_derivatives(:my_processor, foo: "bar")
|
346
368
|
```
|
347
369
|
```rb
|
348
|
-
Attacher.
|
370
|
+
Attacher.derivatives :my_processor do |original, **options|
|
349
371
|
options #=> { :foo => "bar" }
|
350
372
|
# ...
|
351
373
|
end
|
@@ -357,7 +379,7 @@ By default, the `Attacher#process_derivatives` method will download the
|
|
357
379
|
attached file and pass it to the processor:
|
358
380
|
|
359
381
|
```rb
|
360
|
-
Attacher.
|
382
|
+
Attacher.derivatives :my_processor do |original|
|
361
383
|
original #=> #<File:...>
|
362
384
|
# ...
|
363
385
|
end
|
@@ -366,12 +388,22 @@ end
|
|
366
388
|
attacher.process_derivatives(:my_processor) # downloads attached file and passes it to the processor
|
367
389
|
```
|
368
390
|
|
369
|
-
If you want to use a different source file,
|
370
|
-
|
371
|
-
|
391
|
+
If you want to use a different source file, you can pass it in to the process
|
392
|
+
call. Typically you'd pass a local file on disk. If you pass a
|
393
|
+
`Shrine::UploadedFile` object, it will be automatically downloaded to disk.
|
394
|
+
|
395
|
+
```rb
|
396
|
+
# named processor:
|
397
|
+
attacher.process_derivatives(:my_processor, source_file)
|
398
|
+
|
399
|
+
# default processor:
|
400
|
+
attacher.process_derivatives(source_file)
|
401
|
+
```
|
402
|
+
|
403
|
+
If you want to call multiple processors in a row with the same source file, you
|
404
|
+
can use this to avoid re-downloading the same source file each time:
|
372
405
|
|
373
406
|
```rb
|
374
|
-
# this way the source file is downloaded only once
|
375
407
|
attacher.file.download do |original|
|
376
408
|
attacher.process_derivatives(:thumbnails, original)
|
377
409
|
attacher.process_derivatives(:colors, original)
|
@@ -479,9 +511,7 @@ attacher.upload_derivative :thumb, thumbnail_file,
|
|
479
511
|
location: "path/to/derivative"
|
480
512
|
```
|
481
513
|
|
482
|
-
|
483
|
-
name of the derivative, which you can use when extracting metadata, generating
|
484
|
-
location or generating upload options:
|
514
|
+
The `:derivative` name is automatically passed to the uploader:
|
485
515
|
|
486
516
|
```rb
|
487
517
|
class MyUploader < Shrine
|
@@ -510,8 +540,6 @@ If you want to disable this behaviour, pass `delete: false`:
|
|
510
540
|
|
511
541
|
```rb
|
512
542
|
attacher.upload_derivative(:thumb, thumbnail_file, delete: false)
|
513
|
-
|
514
|
-
File.exist?(thumbnail_file.path) #=> true
|
515
543
|
```
|
516
544
|
|
517
545
|
## Merging derivatives
|
@@ -736,7 +764,7 @@ following payload:
|
|
736
764
|
|
737
765
|
A default log subscriber is added as well which logs these events:
|
738
766
|
|
739
|
-
```
|
767
|
+
```
|
740
768
|
Derivatives (2133ms) – {:processor=>:thumbnails, :processor_options=>{}, :uploader=>ImageUploader}
|
741
769
|
```
|
742
770
|
|
@@ -747,7 +775,7 @@ plugin :derivatives, log_subscriber: -> (event) {
|
|
747
775
|
Shrine.logger.info JSON.generate(name: event.name, duration: event.duration, **event.payload)
|
748
776
|
}
|
749
777
|
```
|
750
|
-
```
|
778
|
+
```
|
751
779
|
{"name":"derivatives","duration":2133,"processor":"thumbnails","processor_options":{},"uploader":"ImageUploader"}
|
752
780
|
```
|
753
781
|
|