shrine 3.0.0.rc → 3.0.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 +10 -66
- data/README.md +39 -1061
- data/doc/advantages.md +151 -148
- data/doc/attacher.md +12 -30
- data/doc/carrierwave.md +150 -115
- data/doc/changing_derivatives.md +5 -11
- data/doc/changing_location.md +8 -5
- data/doc/changing_storage.md +5 -2
- data/doc/creating_persistence_plugins.md +9 -6
- data/doc/creating_plugins.md +42 -22
- data/doc/creating_storages.md +4 -1
- data/doc/design.md +7 -5
- data/doc/direct_s3.md +9 -4
- data/doc/external/articles.md +50 -0
- data/doc/external/extensions.md +46 -0
- data/doc/external/misc.md +17 -0
- data/doc/getting_started.md +1038 -0
- data/doc/metadata.md +5 -3
- data/doc/multiple_files.md +55 -29
- data/doc/paperclip.md +206 -163
- data/doc/plugins/activerecord.md +26 -6
- data/doc/plugins/add_metadata.md +4 -2
- data/doc/plugins/atomic_helpers.md +4 -2
- data/doc/plugins/backgrounding.md +83 -44
- data/doc/plugins/cached_attachment_data.md +4 -2
- data/doc/plugins/column.md +4 -2
- data/doc/plugins/data_uri.md +10 -6
- data/doc/plugins/default_storage.md +5 -3
- data/doc/plugins/default_url.md +4 -2
- data/doc/plugins/delete_raw.md +4 -2
- data/doc/plugins/derivation_endpoint.md +63 -39
- data/doc/plugins/derivatives.md +13 -50
- data/doc/plugins/determine_mime_type.md +6 -4
- data/doc/plugins/download_endpoint.md +6 -3
- data/doc/plugins/dynamic_storage.md +4 -2
- data/doc/plugins/entity.md +6 -4
- data/doc/plugins/form_assign.md +4 -2
- data/doc/plugins/included.md +4 -2
- data/doc/plugins/infer_extension.md +6 -4
- data/doc/plugins/instrumentation.md +5 -3
- data/doc/plugins/keep_files.md +9 -2
- data/doc/plugins/metadata_attributes.md +5 -3
- data/doc/plugins/mirroring.md +4 -2
- data/doc/plugins/model.md +6 -4
- data/doc/plugins/module_include.md +4 -2
- data/doc/plugins/multi_cache.md +4 -2
- data/doc/plugins/persistence.md +5 -3
- data/doc/plugins/presign_endpoint.md +6 -2
- data/doc/plugins/pretty_location.md +5 -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 +5 -3
- data/doc/plugins/remote_url.md +26 -5
- data/doc/plugins/remove_attachment.md +4 -2
- data/doc/plugins/remove_invalid.md +10 -2
- data/doc/plugins/restore_cached_data.md +9 -3
- data/doc/plugins/sequel.md +26 -6
- data/doc/plugins/signature.md +6 -4
- data/doc/plugins/store_dimensions.md +6 -4
- data/doc/plugins/tempfile.md +4 -2
- data/doc/plugins/upload_endpoint.md +6 -2
- data/doc/plugins/upload_options.md +6 -4
- data/doc/plugins/url_options.md +4 -2
- data/doc/plugins/validation.md +7 -3
- data/doc/plugins/validation_helpers.md +13 -10
- data/doc/plugins/versions.md +4 -8
- data/doc/processing.md +27 -9
- data/doc/refile.md +119 -127
- data/doc/release_notes/1.0.0.md +4 -0
- data/doc/release_notes/1.1.0.md +4 -0
- 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 +4 -0
- 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 +10 -6
- 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 +7 -4
- 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 +120 -38
- data/doc/retrieving_uploads.md +4 -1
- data/doc/securing_uploads.md +4 -1
- data/doc/storage/file_system.md +12 -4
- data/doc/storage/s3.md +4 -2
- data/doc/testing.md +27 -41
- data/doc/upgrading_to_3.md +105 -26
- data/doc/validation.md +8 -6
- data/lib/shrine/attacher.rb +2 -2
- data/lib/shrine/attachment.rb +7 -10
- data/lib/shrine/plugins/activerecord.rb +10 -10
- data/lib/shrine/plugins/add_metadata.rb +1 -3
- data/lib/shrine/plugins/atomic_helpers.rb +6 -8
- data/lib/shrine/plugins/backgrounding.rb +4 -6
- data/lib/shrine/plugins/cached_attachment_data.rb +1 -3
- data/lib/shrine/plugins/column.rb +2 -4
- data/lib/shrine/plugins/data_uri.rb +1 -3
- data/lib/shrine/plugins/default_storage.rb +1 -3
- data/lib/shrine/plugins/default_url.rb +1 -3
- data/lib/shrine/plugins/delete_raw.rb +1 -3
- data/lib/shrine/plugins/derivation_endpoint.rb +3 -4
- data/lib/shrine/plugins/derivatives.rb +2 -4
- data/lib/shrine/plugins/determine_mime_type.rb +1 -3
- data/lib/shrine/plugins/download_endpoint.rb +1 -3
- data/lib/shrine/plugins/dynamic_storage.rb +1 -3
- data/lib/shrine/plugins/entity.rb +25 -9
- data/lib/shrine/plugins/form_assign.rb +1 -3
- data/lib/shrine/plugins/included.rb +1 -3
- data/lib/shrine/plugins/infer_extension.rb +1 -3
- data/lib/shrine/plugins/instrumentation.rb +1 -3
- data/lib/shrine/plugins/keep_files.rb +1 -3
- data/lib/shrine/plugins/metadata_attributes.rb +1 -3
- data/lib/shrine/plugins/mirroring.rb +2 -1
- data/lib/shrine/plugins/model.rb +2 -4
- data/lib/shrine/plugins/module_include.rb +1 -3
- data/lib/shrine/plugins/multi_cache.rb +3 -3
- data/lib/shrine/plugins/presign_endpoint.rb +1 -3
- data/lib/shrine/plugins/pretty_location.rb +1 -3
- data/lib/shrine/plugins/processing.rb +1 -3
- data/lib/shrine/plugins/rack_file.rb +1 -3
- data/lib/shrine/plugins/rack_response.rb +1 -3
- data/lib/shrine/plugins/recache.rb +1 -3
- data/lib/shrine/plugins/refresh_metadata.rb +1 -3
- data/lib/shrine/plugins/remote_url.rb +1 -3
- data/lib/shrine/plugins/remove_attachment.rb +1 -3
- data/lib/shrine/plugins/remove_invalid.rb +1 -3
- data/lib/shrine/plugins/restore_cached_data.rb +1 -3
- data/lib/shrine/plugins/sequel.rb +10 -12
- data/lib/shrine/plugins/signature.rb +1 -3
- data/lib/shrine/plugins/store_dimensions.rb +1 -3
- data/lib/shrine/plugins/tempfile.rb +1 -3
- data/lib/shrine/plugins/upload_endpoint.rb +1 -3
- data/lib/shrine/plugins/upload_options.rb +1 -3
- data/lib/shrine/plugins/url_options.rb +1 -3
- data/lib/shrine/plugins/validation.rb +1 -3
- data/lib/shrine/plugins/validation_helpers.rb +1 -3
- data/lib/shrine/plugins/versions.rb +1 -3
- data/lib/shrine/storage/file_system.rb +1 -1
- data/lib/shrine/storage/linter.rb +1 -1
- data/lib/shrine/storage/memory.rb +2 -1
- data/lib/shrine/storage/s3.rb +3 -3
- data/lib/shrine/version.rb +1 -1
- metadata +8 -4
data/doc/advantages.md
CHANGED
@@ -1,9 +1,13 @@
|
|
1
|
-
|
1
|
+
---
|
2
|
+
title: Advantages of Shrine
|
3
|
+
---
|
2
4
|
|
3
|
-
There are many existing file upload solutions for Ruby out there
|
4
|
-
|
5
|
-
|
6
|
-
|
5
|
+
There are many existing file upload solutions for Ruby out there. This guide
|
6
|
+
will attempt to cover some of the main advantages that Shrine offers compared
|
7
|
+
to these alternatives.
|
8
|
+
|
9
|
+
For a more direct comparison with specific file attachment libraries, there are
|
10
|
+
more specialized guides for [CarrierWave], [Paperclip], and [Refile] users.
|
7
11
|
|
8
12
|
## Generality
|
9
13
|
|
@@ -11,15 +15,15 @@ Many alternative file upload solutions are coupled to either Rails (Active
|
|
11
15
|
Storage) or Active Record itself (Paperclip, Dragonfly). This is not ideal, as
|
12
16
|
Rails-specific solutions fragment the Ruby community between developers that
|
13
17
|
use Rails and developers that don't. There are many great web frameworks
|
14
|
-
([Sinatra], [Roda], [Cuba], [Hanami], [Grape]) and
|
15
|
-
([Sequel], [ROM], [Hanami::Model]) out there that people use instead of
|
16
|
-
|
18
|
+
([Sinatra], [Roda], [Cuba], [Hanami], [Grape]) and persistence libraries
|
19
|
+
([Sequel], [ROM], [Hanami::Model]) out there that people use instead of Rails
|
20
|
+
and Active Record.
|
17
21
|
|
18
22
|
Shrine, on the other hand, doesn't make any assumptions about which web
|
19
|
-
framework or
|
20
|
-
on top of [Rack], the Ruby web server interface that powers all
|
21
|
-
Ruby web frameworks (including Rails). The integrations for
|
22
|
-
provided as plugins.
|
23
|
+
framework or persistence library you're using. Any web-specific functionality
|
24
|
+
is implemented on top of [Rack], the Ruby web server interface that powers all
|
25
|
+
the popular Ruby web frameworks (including Rails). The integrations for
|
26
|
+
specific ORMs are provided as plugins.
|
23
27
|
|
24
28
|
```rb
|
25
29
|
# Rack-based plugins
|
@@ -34,51 +38,57 @@ Shrine.plugin :rack_file
|
|
34
38
|
Shrine.plugin :activerecord
|
35
39
|
Shrine.plugin :sequel
|
36
40
|
Shrine.plugin :mongoid # https://github.com/shrinerb/shrine-mongoid
|
41
|
+
Shrine.plugin :rom # https://github.com/shrinerb/shrine-rom
|
37
42
|
Shrine.plugin :hanami # https://github.com/katafrakt/hanami-shrine
|
38
43
|
```
|
39
44
|
|
40
45
|
## Simplicity
|
41
46
|
|
42
47
|
Where some popular file attachment libraries have [god objects]
|
43
|
-
(`CarrierWave::Uploader::Base` and `Paperclip::Attachment`), Shrine
|
44
|
-
|
48
|
+
(`CarrierWave::Uploader::Base` and `Paperclip::Attachment`), Shrine distributes
|
49
|
+
responsibilities across multiple core classes:
|
45
50
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
+
| Class | Description |
|
52
|
+
| :---- | :----------- |
|
53
|
+
| `Shrine::Storage::*` | Encapsulate file operations for the underlying service |
|
54
|
+
| `Shrine` | Wraps uploads and handles loading plugins |
|
55
|
+
| `Shrine::UploadedFile` | Represents a file that was uploaded to a storage |
|
56
|
+
| `Shrine::Attacher` | Handles attaching files to records |
|
57
|
+
| `Shrine::Attachment` | Adds convenience attachment methods to model instances |
|
51
58
|
|
52
59
|
```rb
|
53
|
-
photo.image
|
54
|
-
photo.image.storage
|
55
|
-
photo.image.uploader
|
56
|
-
photo.image_attacher
|
60
|
+
photo.image #=> #<Shrine::UploadedFile>
|
61
|
+
photo.image.storage #=> #<Shrine::Storage::S3>
|
62
|
+
photo.image.uploader #=> #<Shrine>
|
63
|
+
photo.image_attacher #=> #<Shrine::Attacher>
|
64
|
+
photo.class.ancestors #=> [..., #<Shrine::Attachment(:image)>, ...]
|
57
65
|
```
|
58
66
|
|
59
67
|
The attachment functionality is decoupled from persistence and storage, which
|
60
68
|
makes it much easier to reason about. Also, special care was taken to make
|
61
|
-
integrating new storages and
|
69
|
+
integrating new storages and persistence libraries as easy as possible.
|
62
70
|
|
63
71
|
## Modularity
|
64
72
|
|
65
73
|
Shrine uses a [plugin system] that allows you to pick and choose the features
|
66
74
|
that you want. Moreover, you'll only be loading code for the features you've
|
67
|
-
selected, which means that Shrine will generally much faster than the
|
75
|
+
selected, which means that Shrine will generally load much faster than the
|
68
76
|
alternatives.
|
69
77
|
|
70
78
|
```rb
|
71
79
|
Shrine.plugin :instrumentation
|
72
80
|
|
73
|
-
# translates to
|
81
|
+
# which translates to
|
74
82
|
|
75
83
|
require "shrine/plugins/instrumentation"
|
76
84
|
Shrine.plugin Shrine::Plugins::Instrumentation
|
77
85
|
```
|
86
|
+
```rb
|
87
|
+
Shrine.method(:instrument).owner #=> Shrine::Plugins::Instrumentation::ClassMethods
|
88
|
+
```
|
78
89
|
|
79
90
|
Shrine recommends a certain type of attachment flow, but it still offers good
|
80
|
-
low-level abstractions that give you the flexibility to build your own
|
81
|
-
attachment flow.
|
91
|
+
low-level abstractions that give you the flexibility to build your own flow.
|
82
92
|
|
83
93
|
```rb
|
84
94
|
uploaded_file = ImageUploader.upload(image, :store) # metadata extraction, upload location generation
|
@@ -113,9 +123,6 @@ Shrine.plugin :determine_mime_type, analyzer: :marcel
|
|
113
123
|
Shrine.plugin :store_dimensions, analyzer: :mini_magick
|
114
124
|
```
|
115
125
|
|
116
|
-
This approach gives you control over your dependencies by allowing you to
|
117
|
-
choose the combination that best suits your needs.
|
118
|
-
|
119
126
|
## Inheritance
|
120
127
|
|
121
128
|
Shrine is designed to handle any types of files. If you're accepting uploads of
|
@@ -126,9 +133,9 @@ for handling them will differ:
|
|
126
133
|
* you might want to store different files to different storage services (images, documents, audios, videos)
|
127
134
|
* extracting metadata might require different tools depending on the filetype
|
128
135
|
|
129
|
-
With Shrine you can create isolated uploaders for each type of file.
|
130
|
-
|
131
|
-
other plugins
|
136
|
+
With Shrine you can create isolated uploaders for each type of file. For
|
137
|
+
features you want all uploaders to share, their plugins can be loaded globally,
|
138
|
+
while other plugins you can load only for selected uploaders.
|
132
139
|
|
133
140
|
```rb
|
134
141
|
# loaded for all plugins
|
@@ -150,18 +157,17 @@ end
|
|
150
157
|
|
151
158
|
## Processing
|
152
159
|
|
153
|
-
Most file attachment libraries
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
raw images).
|
160
|
+
Most file attachment libraries provide either processing files up front
|
161
|
+
(Paperclip, CarrierWave) or on-the-fly (Dragonfly, Refile, Active Storage).
|
162
|
+
However, each approach is suitable for different requirements. For instance,
|
163
|
+
while on-the-fly processing is suitable for fast processing (image thumbnails,
|
164
|
+
document previews), longer running processing (video transcoding, raw images)
|
165
|
+
should be moved into a background job.
|
160
166
|
|
161
|
-
|
162
|
-
|
163
|
-
you can choose to either generate a set of pre-defined
|
164
|
-
|
167
|
+
That's why Shrine supports both [up front][derivatives] and
|
168
|
+
[on-the-fly][derivation_endpoint] processing. For example, if you're handling
|
169
|
+
image uploads, you can choose to either generate a set of pre-defined
|
170
|
+
thumbnails during attachment:
|
165
171
|
|
166
172
|
```rb
|
167
173
|
class ImageUploader < Shrine
|
@@ -177,8 +183,8 @@ class ImageUploader < Shrine
|
|
177
183
|
end
|
178
184
|
```
|
179
185
|
```rb
|
180
|
-
photo.
|
181
|
-
#=> "https://s3.amazonaws.com/path/to/large.jpg"
|
186
|
+
photo.image_derivatives! # creates thumbnails
|
187
|
+
photo.image_url(:large) #=> "https://s3.amazonaws.com/path/to/large.jpg"
|
182
188
|
```
|
183
189
|
|
184
190
|
or generate thumbnails on-demand:
|
@@ -197,42 +203,43 @@ photo.image.derivation_url(:thumbnail, 600, 400)
|
|
197
203
|
#=> ".../thumbnail/600/400/eyJpZCI6ImZvbyIsInN0b3JhZ2UiOiJzdG9yZSJ9?signature=..."
|
198
204
|
```
|
199
205
|
|
200
|
-
###
|
206
|
+
### ImageMagick
|
201
207
|
|
202
208
|
Many file attachment libraries, such as CarrierWave, Paperclip, Dragonfly and
|
203
|
-
Refile, implement their own image processing macros.
|
204
|
-
|
205
|
-
|
206
|
-
While the ImageProcessing gem was created for Shrine, it's completely generic
|
207
|
-
and can be used standalone or with any other file upload library (e.g. Active
|
208
|
-
Storage 6+ uses it). It takes care of many details for you, such as [auto
|
209
|
-
orienting] the input image and [sharpening] the thumbnails after they are
|
210
|
-
resized.
|
209
|
+
Refile, implement their own image processing macros. Rather than building yet
|
210
|
+
another in-house implementation, a general purpose **[ImageProcessing]** gem
|
211
|
+
was created instead, which works great with Shrine.
|
211
212
|
|
212
213
|
```rb
|
213
|
-
require "image_processing"
|
214
|
+
require "image_processing/mini_magick"
|
214
215
|
|
215
216
|
thumbnail = ImageProcessing::MiniMagick
|
216
217
|
.source(image)
|
217
218
|
.resize_to_limit(400, 400)
|
218
219
|
.call # convert input.jpg -auto-orient -resize 400x400> -sharpen 0x1 output.jpg
|
219
220
|
|
220
|
-
thumbnail #=> #<Tempfile:/var/folders/.../image_processing20180316-18446-1j247h6.
|
221
|
+
thumbnail #=> #<Tempfile:/var/folders/.../image_processing20180316-18446-1j247h6.jpg>
|
221
222
|
```
|
222
223
|
|
223
|
-
|
224
|
+
It takes care of many details for you, such as [auto orienting] the input image
|
225
|
+
and applying [sharpening] to resized images. It also has support for
|
226
|
+
[libvips](#libvips).
|
227
|
+
|
228
|
+
### libvips
|
224
229
|
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
230
|
+
**[libvips]** is a full-featured image processing library like ImageMagick,
|
231
|
+
with [great performance characteristics][libvips performance]. It's often
|
232
|
+
**multiple times faster** than ImageMagick, and also has lower memory usage.
|
233
|
+
For more details, see [Why is libvips quick].
|
229
234
|
|
230
|
-
The
|
231
|
-
`ImageProcessing::
|
235
|
+
The ImageProcessing gem provides libvips support as an alternative
|
236
|
+
`ImageProcessing::Vips` backend, sharing the same API as the
|
237
|
+
`ImageProcessing::MiniMagick` backend.
|
232
238
|
|
233
239
|
```rb
|
234
240
|
require "image_processing/vips"
|
235
241
|
|
242
|
+
# this now generates the thumbnail using libvips
|
236
243
|
ImageProcessing::Vips
|
237
244
|
.source(image)
|
238
245
|
.resize_to_limit!(400, 400)
|
@@ -240,13 +247,18 @@ ImageProcessing::Vips
|
|
240
247
|
|
241
248
|
### Other processors
|
242
249
|
|
243
|
-
|
244
|
-
|
245
|
-
|
250
|
+
In contrast to most file attachment libraries, file processing in Shrine is
|
251
|
+
just a functional transformation, where you receive the source file on the
|
252
|
+
input and return processed files on the output. This makes it easier to use
|
253
|
+
custom processing tools and encourages building generic processors that can be
|
254
|
+
reused outside of Shrine.
|
246
255
|
|
247
|
-
|
248
|
-
video transcoding:
|
256
|
+
Here is an example of transcoding videos using the [streamio-ffmpeg] gem:
|
249
257
|
|
258
|
+
```rb
|
259
|
+
# Gemfile
|
260
|
+
gem "streamio-ffmpeg"
|
261
|
+
```
|
250
262
|
```rb
|
251
263
|
class VideoUploader < Shrine
|
252
264
|
Attacher.derivatives_processor do |original|
|
@@ -261,6 +273,13 @@ class VideoUploader < Shrine
|
|
261
273
|
end
|
262
274
|
end
|
263
275
|
```
|
276
|
+
```rb
|
277
|
+
movie.video_derivatives! # create derivatives
|
278
|
+
|
279
|
+
movie.video #=> #<Shrine::UploadedFile @id="5a5cd0.mov" ...>
|
280
|
+
movie.video(:transcoded) #=> #<Shrine::UploadedFile @id="7481d6.mp4" ...>
|
281
|
+
movie.video(:screenshot) #=> #<Shrine::UploadedFile @id="8f3136.jpg" ...>
|
282
|
+
```
|
264
283
|
|
265
284
|
## Metadata & Validation
|
266
285
|
|
@@ -302,13 +321,14 @@ end
|
|
302
321
|
|
303
322
|
## Backgrounding
|
304
323
|
|
305
|
-
In most file upload solutions background processing was an
|
306
|
-
resulted in complex implementations. Shrine
|
307
|
-
feature in mind from day one. It is supported
|
308
|
-
[`backgrounding`][backgrounding] plugin and can be used with [any
|
309
|
-
library][backgrounding libraries].
|
324
|
+
In most file upload solutions, support for background processing was an
|
325
|
+
afterthought, which resulted in complex and unreliable implementations. Shrine
|
326
|
+
was designed with backgrounding feature in mind from day one. It is supported
|
327
|
+
via the [`backgrounding`][backgrounding] plugin and can be used with [any
|
328
|
+
backgrounding library][backgrounding libraries].
|
310
329
|
|
311
330
|
```rb
|
331
|
+
Shrine.plugin :backgrounding
|
312
332
|
Shrine::Attacher.promote_block do
|
313
333
|
PromoteJob.perform_async(self.class.name, record.class.name, record.id, name, file_data)
|
314
334
|
end
|
@@ -324,68 +344,47 @@ class PromoteJob
|
|
324
344
|
attacher = attacher_class.retrieve(model: record, name: name, file: file_data)
|
325
345
|
attacher.create_derivatives # perform processing
|
326
346
|
attacher.atomic_promote
|
347
|
+
rescue Shrine::AttachmentChanged, ActiveRecord::RecordNotFound
|
348
|
+
# attachment changes are detected for concurrency safety
|
327
349
|
end
|
328
350
|
end
|
329
351
|
```
|
330
352
|
|
353
|
+
With Shrine, there is no need for a separate boolean column that indicates the
|
354
|
+
processing status. Processed file data is stored into the attachment database
|
355
|
+
column, which allows you to easily check whether a file has been processed.
|
356
|
+
|
357
|
+
```rb
|
358
|
+
photo = Photo.create(image: file) # background job is kicked off
|
359
|
+
|
360
|
+
photo.image(:large) #=> nil (thumbnails are still being processed)
|
361
|
+
# ... sometime later ...
|
362
|
+
photo.image(:large) #=> #<Shrine::UploadedFile> (processing has finished)
|
363
|
+
```
|
364
|
+
|
331
365
|
## Direct Uploads
|
332
366
|
|
333
|
-
Shrine
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
So, if you're expecting large file uploads, you can use Uppy as a [JavaScript
|
356
|
-
client][Uppy Tus] and have it upload to [Ruby server][tus-ruby-server], then
|
357
|
-
attach uploaded files using the handy [Shrine integration][shrine-tus]. Shrine
|
358
|
-
handles uploads and downloads in a streaming fashion, so you can expect low
|
359
|
-
memory usage.
|
360
|
-
|
361
|
-
Alternatively, you can have [resumable multipart uploads directly to
|
362
|
-
S3][uppy-s3_multipart].
|
363
|
-
|
364
|
-
## Summary
|
365
|
-
|
366
|
-
Shrine is general purpose, it can integrate with any web framework and any
|
367
|
-
database library. It has core classes with clearly defined responsibilities,
|
368
|
-
which provide both higher and lower level abstractions. The functionality is
|
369
|
-
very modular, you can pick and choose features that you need.
|
370
|
-
|
371
|
-
With Shrine you can process both on attachment and on-the-fly, depending on
|
372
|
-
what is more suitable for your requirements. Processing is just a functional
|
373
|
-
transformation, which makes it easier to use the processing tool of your
|
374
|
-
choice. You can also move processing into a background job.
|
375
|
-
|
376
|
-
Shrine automatically extracts metadata from the main file and any processed
|
377
|
-
files. In addition to built-in metadata you can also extract any custom
|
378
|
-
metadata. Any extracted metadata can be validated on attachment.
|
379
|
-
|
380
|
-
Finally, Shrine integrates with Uppy, a full-featured JavaScript file upload
|
381
|
-
library. It allows you to do direct uploads to your app or to S3. For large
|
382
|
-
files you can also make the uploads resumable.
|
383
|
-
|
384
|
-
[Paperclip]: https://github.com/thoughtbot/paperclip
|
385
|
-
[CarrierWave]: https://github.com/carrierwaveuploader/carrierwave
|
386
|
-
[Dragonfly]: http://markevans.github.io/dragonfly/
|
387
|
-
[Refile]: https://github.com/refile/refile
|
388
|
-
[Active Storage]: https://github.com/rails/rails/tree/master/activestorage#active-storage
|
367
|
+
For client side uploads, Shrine adopts **[Uppy]**, a modern JavaScript file
|
368
|
+
upload library. This gives the developer a lot more power in customizing the
|
369
|
+
user experience compared to a custom JavaScript solution implemented by Refile
|
370
|
+
and Active Storage.
|
371
|
+
|
372
|
+
Uppy supports direct uploads to [AWS S3][Uppy AwsS3] or to a [custom
|
373
|
+
endpoint][Uppy XHRUpload]. It also supports **resumable** uploads, either
|
374
|
+
[directly to S3][Uppy AwsS3Multipart] or via the [tus protocol][tus]. For the
|
375
|
+
UI you can choose from various components, ranging from a simple [status
|
376
|
+
bar][Uppy StatusBar] to a full-featured [dashboard][Uppy Dashboard].
|
377
|
+
|
378
|
+
Shrine provides server side components for each type of upload. They are built
|
379
|
+
on top of Rack, so that they can be used with any Ruby web framework.
|
380
|
+
|
381
|
+
| Uppy | Shrine |
|
382
|
+
| :--- | :----- |
|
383
|
+
| [XHRUpload][Uppy XHRUpload] | [`upload_endpoint`][upload_endpoint] |
|
384
|
+
| [AwsS3][Uppy AwsS3] | [`presign_endpoint`][presign_endpoint] |
|
385
|
+
| [AwsS3Multipart][Uppy AwsS3Multipart] | [`uppy-s3_multipart`][uppy-s3_multipart] |
|
386
|
+
| [Tus][Uppy Tus] | [`tus-ruby-server`][tus-ruby-server] |
|
387
|
+
|
389
388
|
[Rack]: https://rack.github.io
|
390
389
|
[Sinatra]: http://sinatrarb.com
|
391
390
|
[Roda]: http://roda.jeremyevans.net
|
@@ -408,32 +407,36 @@ files you can also make the uploads resumable.
|
|
408
407
|
[MiniMagick]: https://github.com/minimagick/minimagick
|
409
408
|
[ruby-vips]: https://github.com/libvips/ruby-vips
|
410
409
|
[god objects]: https://en.wikipedia.org/wiki/God_object
|
411
|
-
[ImageMagick]: https://www.imagemagick.org
|
412
410
|
[ImageProcessing]: https://github.com/janko/image_processing
|
413
411
|
[auto orienting]: https://www.imagemagick.org/script/command-line-options.php#auto-orient
|
414
412
|
[sharpening]: https://photography.tutsplus.com/tutorials/what-is-image-sharpening--cms-26627
|
415
413
|
[libvips]: http://libvips.github.io/libvips/
|
416
414
|
[Why is libvips quick]: https://github.com/libvips/libvips/wiki/Why-is-libvips-quick
|
417
|
-
[metadata]: /
|
418
|
-
[store_dimensions]: /
|
419
|
-
[add_metadata]: /
|
420
|
-
[validation]: /
|
421
|
-
[upload_endpoint]: /
|
422
|
-
[presign_endpoint]: /
|
415
|
+
[metadata]: https://shrinerb.com/docs/metadata
|
416
|
+
[store_dimensions]: https://shrinerb.com/docs/plugins/store_dimensions
|
417
|
+
[add_metadata]: https://shrinerb.com/docs/plugins/add_metadata
|
418
|
+
[validation]: https://shrinerb.com/docs/validation
|
419
|
+
[upload_endpoint]: https://shrinerb.com/docs/plugins/upload_endpoint
|
420
|
+
[presign_endpoint]: https://shrinerb.com/docs/plugins/presign_endpoint
|
423
421
|
[Uppy]: https://uppy.io
|
424
|
-
[Uppy XHRUpload]: https://uppy.io/docs/
|
422
|
+
[Uppy XHRUpload]: https://uppy.io/docs/xhr-upload/
|
425
423
|
[Uppy AwsS3]: https://uppy.io/docs/aws-s3/
|
426
424
|
[Uppy Tus]: https://uppy.io/docs/tus/
|
425
|
+
[Uppy AwsS3Multipart]: https://uppy.io/docs/aws-s3-multipart/
|
426
|
+
[tus]: https://tus.io
|
427
427
|
[Uppy StatusBar]: https://uppy.io/examples/statusbar/
|
428
428
|
[Uppy Dashboard]: https://uppy.io/examples/dashboard/
|
429
|
-
[backgrounding]: /doc/plugins/backgrounding.md#readme
|
430
|
-
[backgrounding libraries]: https://github.com/shrinerb/shrine/wiki/Backgrounding-Libraries
|
431
|
-
[Down streaming]: https://github.com/janko/down#streaming
|
432
|
-
[Transloadit]: https://transloadit.com
|
433
|
-
[tus]: https://tus.io
|
434
|
-
[tus implementations]: https://tus.io/implementations.html
|
435
429
|
[tus-ruby-server]: https://github.com/janko/tus-ruby-server
|
436
|
-
[shrine-tus]: https://github.com/shrinerb/shrine-tus
|
437
430
|
[uppy-s3_multipart]: https://github.com/janko/uppy-s3_multipart
|
438
|
-
[
|
439
|
-
[
|
431
|
+
[backgrounding]: https://shrinerb.com/docs/plugins/backgrounding
|
432
|
+
[backgrounding libraries]: https://github.com/shrinerb/shrine/wiki/Backgrounding-Libraries
|
433
|
+
[Down streaming]: https://github.com/janko/down#streaming
|
434
|
+
[validation_helpers]: https://shrinerb.com/docs/plugins/validation_helpers
|
435
|
+
[custom validations]: https://shrinerb.com/docs/validation#custom-validations
|
436
|
+
[derivatives]: https://shrinerb.com/docs/plugins/derivatives
|
437
|
+
[derivation_endpoint]: https://shrinerb.com/docs/plugins/derivation_endpoint
|
438
|
+
[libvips performance]: https://github.com/libvips/libvips/wiki/Speed-and-memory-use#results
|
439
|
+
[streamio-ffmpeg]: https://github.com/streamio/streamio-ffmpeg
|
440
|
+
[CarrierWave]: https://shrinerb.com/docs/carrierwave
|
441
|
+
[Paperclip]: https://shrinerb.com/docs/paperclip
|
442
|
+
[Refile]: https://shrinerb.com/docs/refile
|
data/doc/attacher.md
CHANGED
@@ -1,27 +1,9 @@
|
|
1
|
-
|
1
|
+
---
|
2
|
+
title: Using Attacher
|
3
|
+
---
|
2
4
|
|
3
5
|
This guide explains what is `Shrine::Attacher` and how to use it.
|
4
6
|
|
5
|
-
## Contents
|
6
|
-
|
7
|
-
* [Introduction](#introduction)
|
8
|
-
* [Storage](#storage)
|
9
|
-
* [Attaching](#attaching)
|
10
|
-
- [Attaching cached](#attaching-cached)
|
11
|
-
- [Attaching stored](#attaching-stored)
|
12
|
-
- [Uploading](#uploading)
|
13
|
-
- [Changes](#changes)
|
14
|
-
* [Finalizing](#finalizing)
|
15
|
-
- [Promoting](#promoting)
|
16
|
-
- [Replacing](#replacing)
|
17
|
-
* [Retrieving](#retreiving)
|
18
|
-
- [File](#file)
|
19
|
-
- [Attached](#attached)
|
20
|
-
- [URL](#url)
|
21
|
-
- [Data](#data)
|
22
|
-
* [Deleting](#deleting)
|
23
|
-
* [Context](#context)
|
24
|
-
|
25
7
|
## Introduction
|
26
8
|
|
27
9
|
The attachment logic is handled by a `Shrine::Attacher` object. The
|
@@ -47,10 +29,10 @@ attacher.file # called by `photo.image`
|
|
47
29
|
attacher.url # called by `photo.image_url`
|
48
30
|
```
|
49
31
|
|
50
|
-
The `model
|
51
|
-
`Shrine::Attacher` methods (such as
|
52
|
-
above), but in this guide we'll focus only
|
53
|
-
methods.
|
32
|
+
The [`model`][model], [`entity`][entity], and [`column`][column] plugins
|
33
|
+
provide additional `Shrine::Attacher` methods (such as
|
34
|
+
`Shrine::Attacher.from_model` we see above), but in this guide we'll focus only
|
35
|
+
on the core `Shrine::Attacher` methods.
|
54
36
|
|
55
37
|
So, we'll assume a `Shrine::Attacher` object not backed by any model/entity:
|
56
38
|
|
@@ -446,8 +428,8 @@ However, it's generally better practice to pass uploader options directly to
|
|
446
428
|
`Attacher#assign`, `Attacher#attach`, `Attacher#promote` or any other method
|
447
429
|
that's calling `Attacher#upload`.
|
448
430
|
|
449
|
-
[validation]: /
|
450
|
-
[column]: /
|
451
|
-
[entity]: /
|
452
|
-
[model]: /
|
453
|
-
[backgrounding]: /
|
431
|
+
[validation]: https://shrinerb.com/docs/plugins/validation
|
432
|
+
[column]: https://shrinerb.com/docs/plugins/column
|
433
|
+
[entity]: https://shrinerb.com/docs/plugins/entity
|
434
|
+
[model]: https://shrinerb.com/docs/plugins/model
|
435
|
+
[backgrounding]: https://shrinerb.com/docs/plugins/backgrounding
|