shrine 0.9.0 → 1.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/README.md +70 -59
- data/doc/carrierwave.md +436 -0
- data/doc/direct_s3.md +20 -1
- data/doc/paperclip.md +308 -0
- data/doc/regenerating_versions.md +76 -11
- data/lib/shrine.rb +42 -46
- data/lib/shrine/plugins/activerecord.rb +12 -6
- data/lib/shrine/plugins/background_helpers.rb +5 -5
- data/lib/shrine/plugins/default_storage.rb +1 -1
- data/lib/shrine/plugins/default_url_options.rb +31 -0
- data/lib/shrine/plugins/determine_mime_type.rb +13 -3
- data/lib/shrine/plugins/direct_upload.rb +55 -106
- data/lib/shrine/plugins/hooks.rb +33 -11
- data/lib/shrine/plugins/keep_files.rb +4 -19
- data/lib/shrine/plugins/logging.rb +16 -11
- data/lib/shrine/plugins/migration_helpers.rb +4 -4
- data/lib/shrine/plugins/module_include.rb +46 -0
- data/lib/shrine/plugins/moving.rb +0 -11
- data/lib/shrine/plugins/multi_delete.rb +3 -12
- data/lib/shrine/plugins/parsed_json.rb +22 -0
- data/lib/shrine/plugins/rack_file.rb +63 -0
- data/lib/shrine/plugins/recache.rb +1 -1
- data/lib/shrine/plugins/restore_cached.rb +1 -2
- data/lib/shrine/plugins/sequel.rb +9 -3
- data/lib/shrine/plugins/validation_helpers.rb +1 -1
- data/lib/shrine/plugins/versions.rb +30 -17
- data/lib/shrine/storage/file_system.rb +62 -17
- data/lib/shrine/storage/linter.rb +8 -3
- data/lib/shrine/storage/s3.rb +84 -20
- data/lib/shrine/version.rb +2 -2
- data/shrine.gemspec +11 -8
- metadata +31 -40
- data/lib/shrine/plugins/delete_invalid.rb +0 -25
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 583eed751bfa6c1ae0ad5d9495509091563a8c02
|
4
|
+
data.tar.gz: 9c82a62a10a45df20f3f4d9422066beb705cfa39
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 68e093c6b118b379383305bfede12fd5710342c82c6b66040661be744d6995a723147f3b426b0d8afc03009c35d3b21a529232822e9232d2c25531d831fd973b
|
7
|
+
data.tar.gz: 41fabbd7fa515c3eb992bbbf5205fd924d502c64ec6f430d053ef135512e2476797435a5a4642fd066ea9bd8ba0b375455317a6bc54aaabcf24b557841b98de1
|
data/README.md
CHANGED
@@ -2,12 +2,15 @@
|
|
2
2
|
|
3
3
|
Shrine is a toolkit for file uploads in Ruby applications.
|
4
4
|
|
5
|
+
If you're new, you're encouraged to read the [introductory blog post] which
|
6
|
+
explains the motivation behind Shrine.
|
7
|
+
|
5
8
|
## Resources
|
6
9
|
|
7
10
|
* Documentation: [shrinerb.com](http://shrinerb.com)
|
8
11
|
* Source: [github.com/janko-m/shrine](https://github.com/janko-m/shrine)
|
9
12
|
* Bugs: [github.com/janko-m/shrine/issues](https://github.com/janko-m/shrine/issues)
|
10
|
-
*
|
13
|
+
* Help & Dicussion: [groups.google.com/group/ruby-shrine](https://groups.google.com/forum/#!forum/ruby-shrine)
|
11
14
|
|
12
15
|
## Installation
|
13
16
|
|
@@ -15,7 +18,7 @@ Shrine is a toolkit for file uploads in Ruby applications.
|
|
15
18
|
gem "shrine"
|
16
19
|
```
|
17
20
|
|
18
|
-
Shrine has been tested on MRI 2.1, MRI 2.2 and
|
21
|
+
Shrine has been tested on MRI 2.1, MRI 2.2, JRuby and Rubinius.
|
19
22
|
|
20
23
|
## Basics
|
21
24
|
|
@@ -31,7 +34,7 @@ uploader = Shrine.new(:file_system)
|
|
31
34
|
|
32
35
|
uploaded_file = uploader.upload(File.open("avatar.jpg"))
|
33
36
|
uploaded_file #=> #<Shrine::UploadedFile>
|
34
|
-
uploaded_file.url #=> "uploads/9260ea09d8effd.jpg"
|
37
|
+
uploaded_file.url #=> "/uploads/9260ea09d8effd.jpg"
|
35
38
|
uploaded_file.data #=>
|
36
39
|
# {
|
37
40
|
# "storage" => "file_system",
|
@@ -55,32 +58,39 @@ to be an actual IO, it's enough that it responds to these 5 methods:
|
|
55
58
|
`#read(*args)`, `#size`, `#eof?`, `#rewind` and `#close`.
|
56
59
|
`ActionDispatch::Http::UploadedFile` is one such object.
|
57
60
|
|
58
|
-
|
61
|
+
The returned `Shrine::UploadedFile` represents the file that has been uploaded,
|
62
|
+
and we can do a lot with it:
|
59
63
|
|
60
64
|
```rb
|
61
|
-
|
62
|
-
|
65
|
+
uploaded_file.url #=> "/uploads/938kjsdf932.jpg"
|
66
|
+
uploaded_file.read #=> "..."
|
67
|
+
uploaded_file.exists? #=> true
|
68
|
+
uploaded_file.download #=> #<Tempfile:/var/folders/k7/6zx6dx6x7ys3rv3srh0nyfj00000gn/T/20151004-74201-1t2jacf>
|
69
|
+
uploaded_file.metadata #=> {...}
|
63
70
|
```
|
64
71
|
|
65
|
-
|
72
|
+
To read about the metadata that is stored with the uploaded file, see the
|
73
|
+
[metadata](#metadata) section. Once you're done with the file, you can delete
|
74
|
+
it.
|
66
75
|
|
67
76
|
```rb
|
68
|
-
|
69
|
-
uploaded_file.exists? #=> false
|
77
|
+
uploaded_file.delete
|
70
78
|
```
|
71
79
|
|
72
80
|
## Attachment
|
73
81
|
|
74
|
-
In web applications, instead of managing files directly, we want to
|
75
|
-
as "attachments" to models and to tie them to the lifecycle of
|
76
|
-
|
82
|
+
In web applications, instead of managing files directly, we rather want to
|
83
|
+
treat them as "attachments" to models and to tie them to the lifecycle of
|
84
|
+
records. In Shrine we do this by generating and including "attachment" modules.
|
77
85
|
|
78
86
|
Firstly we need to assign the special `:cache` and `:store` storages:
|
79
87
|
|
80
88
|
```rb
|
89
|
+
require "shrine/storage/file_system"
|
90
|
+
|
81
91
|
Shrine.storages = {
|
82
|
-
cache: Shrine::Storage::FileSystem.new(
|
83
|
-
store: Shrine::Storage::FileSystem.new("public", subdirectory: "uploads"),
|
92
|
+
cache: Shrine::Storage::FileSystem.new("public", subdirectory: "uploads/cache"),
|
93
|
+
store: Shrine::Storage::FileSystem.new("public", subdirectory: "uploads/store"),
|
84
94
|
}
|
85
95
|
```
|
86
96
|
|
@@ -89,7 +99,7 @@ uploading:
|
|
89
99
|
|
90
100
|
```rb
|
91
101
|
class ImageUploader < Shrine
|
92
|
-
#
|
102
|
+
# logic for uploading images
|
93
103
|
end
|
94
104
|
```
|
95
105
|
|
@@ -111,12 +121,7 @@ user = User.new
|
|
111
121
|
user.avatar = File.open("avatar.jpg") # uploads the file to `:cache`
|
112
122
|
user.avatar #=> #<Shrine::UploadedFile>
|
113
123
|
user.avatar_url #=> "/uploads/9260ea09d8effd.jpg"
|
114
|
-
user.avatar_data #=>
|
115
|
-
# {
|
116
|
-
# "storage" => "cache",
|
117
|
-
# "id" => "9260ea09d8effd.jpg",
|
118
|
-
# "metadata" => {...},
|
119
|
-
# }
|
124
|
+
user.avatar_data #=> "{\"storage\":\"cache\",\"id\":\"9260ea09d8effd.jpg\",\"metadata\":{...}}"
|
120
125
|
```
|
121
126
|
|
122
127
|
The attachment module has added `#avatar`, `#avatar=` and `#avatar_url`
|
@@ -124,11 +129,11 @@ methods to our User. This is what's happening:
|
|
124
129
|
|
125
130
|
```rb
|
126
131
|
Shrine[:avatar] #=> #<Shrine::Attachment(avatar)>
|
127
|
-
Shrine[:avatar].
|
128
|
-
Shrine[:avatar].instance_methods #=> [:avatar=, :avatar, :avatar_url,
|
132
|
+
Shrine[:avatar].is_a?(Module) #=> true
|
133
|
+
Shrine[:avatar].instance_methods #=> [:avatar=, :avatar, :avatar_url, :avatar_attacher]
|
129
134
|
|
130
135
|
Shrine[:document] #=> #<Shrine::Attachment(document)>
|
131
|
-
Shrine[:document].instance_methods #=> [:document=, :document, :document_url,
|
136
|
+
Shrine[:document].instance_methods #=> [:document=, :document, :document_url, :document_attacher]
|
132
137
|
|
133
138
|
# If you prefer to be more explicit, you can use the expanded forms
|
134
139
|
Shrine.attachment(:avatar)
|
@@ -147,7 +152,7 @@ Sequel and ActiveRecord ORMs. Shrine uses the "\<attachment\>\_data" column
|
|
147
152
|
for storing attachments, so you'll need to add it in a migration:
|
148
153
|
|
149
154
|
```rb
|
150
|
-
add_column :users, :avatar_data, :text
|
155
|
+
add_column :users, :avatar_data, :text # or a "jsonb" column if you need querying
|
151
156
|
```
|
152
157
|
```rb
|
153
158
|
Shrine.plugin :sequel
|
@@ -188,7 +193,7 @@ Shrine comes with a `direct_upload` plugin which provides an endpoint
|
|
188
193
|
(implemented in [Roda]) that can be used for AJAX uploads.
|
189
194
|
|
190
195
|
```rb
|
191
|
-
Shrine.plugin :direct_upload #
|
196
|
+
Shrine.plugin :direct_upload # Provides a Roda endpoint
|
192
197
|
```
|
193
198
|
```rb
|
194
199
|
Rails.application.routes.draw do
|
@@ -196,9 +201,17 @@ Rails.application.routes.draw do
|
|
196
201
|
mount ImageUploader.direct_endpoint => "/attachments/images"
|
197
202
|
end
|
198
203
|
```
|
199
|
-
```
|
200
|
-
|
201
|
-
|
204
|
+
```rb
|
205
|
+
# POST /attachments/images/cache/avatar
|
206
|
+
{
|
207
|
+
"id": "43kewit94.jpg",
|
208
|
+
"storage": "cache",
|
209
|
+
"metadata": {
|
210
|
+
"size": 384393,
|
211
|
+
"filename": "nature.jpg",
|
212
|
+
"mime_type": "image/jpeg"
|
213
|
+
}
|
214
|
+
}
|
202
215
|
```
|
203
216
|
|
204
217
|
There are many great JavaScript libraries for AJAX file uploads, for example
|
@@ -212,8 +225,10 @@ $('[type="file"]').fileupload({
|
|
212
225
|
});
|
213
226
|
```
|
214
227
|
|
215
|
-
This
|
216
|
-
|
228
|
+
This is an oversimplified implementation without any UX, it's just to show you
|
229
|
+
how easy it is. The `direct_upload` plugin also provides a route for direct S3
|
230
|
+
uploads, see the [example app] for how you can do multiple uploads directly to
|
231
|
+
S3.
|
217
232
|
|
218
233
|
## Processing
|
219
234
|
|
@@ -237,9 +252,9 @@ assigned and saved, an "upload" actually happens two times. First the file is
|
|
237
252
|
`:store` on save.
|
238
253
|
|
239
254
|
Ok, now how do we do the actual processing? Well, Shrine actually doesn't ship
|
240
|
-
with any
|
241
|
-
belongs in a separate gem.
|
242
|
-
can use with Shrine:
|
255
|
+
with any file processing functionality, because that is a generic problem that
|
256
|
+
belongs in a separate gem. If the type of files you're uploading are images, I
|
257
|
+
created the [image_processing] gem which you can use with Shrine:
|
243
258
|
|
244
259
|
```rb
|
245
260
|
require "image_processing/mini_magick"
|
@@ -249,7 +264,7 @@ class ImageUploader < Shrine
|
|
249
264
|
|
250
265
|
def process(io, context)
|
251
266
|
if context[:phase] == :store
|
252
|
-
|
267
|
+
resize_to_limit(io.download, 700, 700)
|
253
268
|
end
|
254
269
|
end
|
255
270
|
end
|
@@ -266,9 +281,9 @@ storing the original file.
|
|
266
281
|
|
267
282
|
### Versions
|
268
283
|
|
269
|
-
|
270
|
-
For that you just need to load the `versions`
|
271
|
-
you can return a Hash of versions:
|
284
|
+
If you're uploading images, often you'll want to store various thumbnails
|
285
|
+
alongside your original image. For that you just need to load the `versions`
|
286
|
+
plugin, and now in `#process` you can return a Hash of versions:
|
272
287
|
|
273
288
|
```rb
|
274
289
|
require "image_processing/mini_magick"
|
@@ -279,9 +294,9 @@ class ImageUploader < Shrine
|
|
279
294
|
|
280
295
|
def process(io, context)
|
281
296
|
if context[:phase] == :store
|
282
|
-
size_700 =
|
283
|
-
size_500 =
|
284
|
-
size_300 =
|
297
|
+
size_700 = resize_to_limit(io.download, 700, 700)
|
298
|
+
size_500 = resize_to_limit(size_700, 500, 500)
|
299
|
+
size_300 = resize_to_limit(size_500, 300, 300)
|
285
300
|
|
286
301
|
{large: size_700, medium: size_500, small: size_300}
|
287
302
|
end
|
@@ -299,12 +314,6 @@ Now when you access the stored attachment, a Hash of versions will be returned
|
|
299
314
|
instead:
|
300
315
|
|
301
316
|
```rb
|
302
|
-
user.avatar #=>
|
303
|
-
# {
|
304
|
-
# large: #<Shrine::UploadedFile>,
|
305
|
-
# medium: #<Shrine::UploadedFile>,
|
306
|
-
# small: #<Shrine::UploadedFile>,
|
307
|
-
# }
|
308
317
|
user.avatar.class #=> Hash
|
309
318
|
|
310
319
|
# With the store_dimensions plugin
|
@@ -355,13 +364,14 @@ Validations are registered by calling `Shrine::Attacher.validate`, and are best
|
|
355
364
|
done with the `validation_helpers` plugin:
|
356
365
|
|
357
366
|
```rb
|
358
|
-
class
|
367
|
+
class DocumentUploader < Shrine
|
359
368
|
plugin :validation_helpers
|
360
369
|
|
361
370
|
Attacher.validate do
|
362
371
|
# Evaluated inside an instance of Shrine::Attacher.
|
363
372
|
if record.guest?
|
364
|
-
validate_max_size
|
373
|
+
validate_max_size 10*1024*1024, message: "is too large (max is 10 MB)"
|
374
|
+
validate_mime_type_inclusion ["application/pdf"]
|
365
375
|
end
|
366
376
|
end
|
367
377
|
end
|
@@ -369,9 +379,9 @@ end
|
|
369
379
|
|
370
380
|
```rb
|
371
381
|
user = User.new
|
372
|
-
user.
|
382
|
+
user.resume = File.open("resume.pdf")
|
373
383
|
user.valid? #=> false
|
374
|
-
user.errors.to_hash #=> {
|
384
|
+
user.errors.to_hash #=> {resume: ["is too large (max is 2 MB)"]}
|
375
385
|
```
|
376
386
|
|
377
387
|
## Metadata
|
@@ -404,11 +414,11 @@ browser sets solely based on the extension of the uploaded file. This means
|
|
404
414
|
that by default Shrine's "mime_type" is *not* guaranteed to hold the actual
|
405
415
|
MIME type of the file.
|
406
416
|
|
407
|
-
To help with that Shrine provides the `
|
408
|
-
|
417
|
+
To help with that Shrine provides the `determine_mime_type` plugin, which by
|
418
|
+
default uses the UNIX [file] utility to determine the actual MIME type:
|
409
419
|
|
410
420
|
```rb
|
411
|
-
Shrine.plugin :
|
421
|
+
Shrine.plugin :determine_mime_type
|
412
422
|
```
|
413
423
|
```rb
|
414
424
|
user = User.create(avatar: File.open("image.mp4")) # image with a .mp4 extension
|
@@ -417,8 +427,8 @@ user.avatar.mime_type #=> "image/png"
|
|
417
427
|
|
418
428
|
### Dimensions
|
419
429
|
|
420
|
-
|
421
|
-
using the [fastimage] gem.
|
430
|
+
If you're uploading images and you want to store dimensions, you can use the
|
431
|
+
`store_dimensions` plugin which extracts dimensions using the [fastimage] gem.
|
422
432
|
|
423
433
|
```rb
|
424
434
|
ImageUploader.plugin :store_dimensions
|
@@ -463,7 +473,7 @@ end
|
|
463
473
|
## Locations
|
464
474
|
|
465
475
|
By default files will all be put in the same folder. If you want that each
|
466
|
-
|
476
|
+
attachment has its own directory, you can use the `pretty_location` plugin:
|
467
477
|
|
468
478
|
```rb
|
469
479
|
Shrine.plugin :pretty_location
|
@@ -576,14 +586,14 @@ In combination with direct upload for caching, this provides a completely
|
|
576
586
|
seamless user experience. First the user ansynchronosuly caches the file and
|
577
587
|
hopefully sees a nice progress bar. After this is finishes and user submits the
|
578
588
|
form, promoting will be kicked off into a background job, and the record will
|
579
|
-
be saved with the cached
|
589
|
+
be saved with the cached file If your cache is public (e.g. in the "public"
|
580
590
|
folder), the end user will immediately see their uploaded file, because the URL
|
581
591
|
will point to the cached version.
|
582
592
|
|
583
593
|
In the meanwhile, what `#promote` does is it uploads the cached file `:store`,
|
584
594
|
and writes the stored file to the column. When the record gets saved, the URL
|
585
595
|
will switch from filesystem to S3, but the user won't even notice that
|
586
|
-
something happened, because they will still see the same
|
596
|
+
something happened, because they will still see the same file.
|
587
597
|
|
588
598
|
### Generality
|
589
599
|
|
@@ -661,3 +671,4 @@ The gem is available as open source under the terms of the [MIT License].
|
|
661
671
|
[MIT License]: http://opensource.org/licenses/MIT
|
662
672
|
[example app]: https://github.com/janko-m/shrine-example
|
663
673
|
[ships with over 25 plugins]: http://shrinerb.com#plugins
|
674
|
+
[introductory blog post]: http://twin.github.io/introducing-shrine/
|
data/doc/carrierwave.md
ADDED
@@ -0,0 +1,436 @@
|
|
1
|
+
# Shrine for CarrierWave Users
|
2
|
+
|
3
|
+
This guide is aimed at helping CarrierWave users transition to Shrine. We will
|
4
|
+
first generally mention what are the key differences. Afterwards there is an
|
5
|
+
extensive reference of CarrierWave's interface and what is the equivalent in
|
6
|
+
Shrine.
|
7
|
+
|
8
|
+
## Uploaders
|
9
|
+
|
10
|
+
Shrine has a concept of uploaders similar to CarrierWave's, but instead of
|
11
|
+
inheriting from `CarrierWave::Uploader::Base`, you inherit from `Shrine`
|
12
|
+
directly:
|
13
|
+
|
14
|
+
```rb
|
15
|
+
class ImageUploader < Shrine
|
16
|
+
# ...
|
17
|
+
end
|
18
|
+
```
|
19
|
+
|
20
|
+
While in CarrierWave you choose a storages for uploaders directly, in Shrine
|
21
|
+
you first register storages globally (under a symbol name), and then you
|
22
|
+
instantiate uploaders with a specific storage.
|
23
|
+
|
24
|
+
```rb
|
25
|
+
require "shrine/storage/file_system"
|
26
|
+
|
27
|
+
Shrine.storages = {
|
28
|
+
cache: Shrine::Storage::FileSystem.new("public", subdirectory: "uploads/cache"),
|
29
|
+
store: Shrine::Storage::FileSystem.new("public", subdirectory: "uploads/store"),
|
30
|
+
}
|
31
|
+
```
|
32
|
+
```rb
|
33
|
+
cache_uploader = Shrine.new(:cache)
|
34
|
+
store_uploader = Shrine.new(:store)
|
35
|
+
```
|
36
|
+
|
37
|
+
CarrierWave uses symbols for referencing storages (`:file`, `:fog`, ...), but
|
38
|
+
in Shrine you instantiate storages directly. This makes storages much more
|
39
|
+
flexible, because this way they can have their own options that are specific to
|
40
|
+
them.
|
41
|
+
|
42
|
+
### Processing
|
43
|
+
|
44
|
+
In Shrine processing is done instance-level in the `#process` method. To
|
45
|
+
generate versions, you simply return a hash, and also load the `versions`
|
46
|
+
plugin to make your uploader recognize versions:
|
47
|
+
|
48
|
+
```rb
|
49
|
+
require "image_processing/mini_magick" # part of the "image_processing" gem
|
50
|
+
|
51
|
+
class ImageUploader < Shrine
|
52
|
+
include ImageProcessing::MiniMagick
|
53
|
+
plugin :versions, names: [:small, :medium, :large]
|
54
|
+
|
55
|
+
def process(io, context)
|
56
|
+
if context[:phase] == :store
|
57
|
+
thumb = resize_to_limit(io.download, 300, 300)
|
58
|
+
{original: io, thumb: thumb}
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
```
|
63
|
+
|
64
|
+
## Attachments
|
65
|
+
|
66
|
+
Like CarrierWave, Shrine also provides integrations with ORMs, it ships with
|
67
|
+
plugins for both Sequel and ActiveRecord (but it can also be used with simple
|
68
|
+
PORO models).
|
69
|
+
|
70
|
+
```rb
|
71
|
+
Shrine.plugin :sequel # If you're using Sequel
|
72
|
+
Shrine.plugin :activerecord # If you're using ActiveRecord
|
73
|
+
```
|
74
|
+
|
75
|
+
Instead of giving you class methods for "mounting" uploaders, in Shrine you
|
76
|
+
generate "attachment modules" which you include in your models:
|
77
|
+
|
78
|
+
```rb
|
79
|
+
class User < Sequel::Model
|
80
|
+
include ImageUploader[:avatar] # adds `avatar`, `avatar=` and `avatar_url` methods
|
81
|
+
end
|
82
|
+
```
|
83
|
+
|
84
|
+
You models are required to have the `<attachment>_data` column, in the above
|
85
|
+
case `avatar_data`. It contains the storage and location of the file, as well
|
86
|
+
as additional metadata.
|
87
|
+
|
88
|
+
### Multiple uploads
|
89
|
+
|
90
|
+
Shrine doesn't have support for multiple uploads like CarrierWave does, instead
|
91
|
+
it expects that you will implement multiple uploads yourself using a separate
|
92
|
+
model. This is a good thing, because the implementation is specific to the ORM
|
93
|
+
you're using, and it's analogous to how you would implement adding items to any
|
94
|
+
dynamic one-to-many relationship. Take a look at the [example app] which
|
95
|
+
demonstrates how easy it is to implement multiple uploads.
|
96
|
+
|
97
|
+
## CarrierWave to Shrine direct mapping
|
98
|
+
|
99
|
+
### `CarrierWave::Uploader::Base`
|
100
|
+
|
101
|
+
#### `.storage`
|
102
|
+
|
103
|
+
When using models, by default all storages use `:cache` for cache, and `:store`
|
104
|
+
for store. If you want to change that, you can use the `default_storage`
|
105
|
+
plugin:
|
106
|
+
|
107
|
+
```rb
|
108
|
+
Shrine.storages[:dropbox] = Shrine::Storage::Dropbox.new(*args)
|
109
|
+
```
|
110
|
+
|
111
|
+
```rb
|
112
|
+
class ImageUploader
|
113
|
+
plugin :default_storage, store: :dropbox
|
114
|
+
end
|
115
|
+
```
|
116
|
+
|
117
|
+
#### `.process`, `.version`
|
118
|
+
|
119
|
+
As explained in the "Processing" section, processing is done by overriding the
|
120
|
+
`Shrine#process` method.
|
121
|
+
|
122
|
+
#### `.before`, `.after`
|
123
|
+
|
124
|
+
In Shrine you can get callbacks by loading the `hooks` plugin. Unlike
|
125
|
+
CarrierWave, and much like Sequel, Shrine implements callbacks by overriding
|
126
|
+
instance methods:
|
127
|
+
|
128
|
+
```rb
|
129
|
+
class ImageUploader < Shrine
|
130
|
+
plugin :hooks
|
131
|
+
|
132
|
+
def after_upload(io, context)
|
133
|
+
super
|
134
|
+
# do something
|
135
|
+
end
|
136
|
+
end
|
137
|
+
```
|
138
|
+
|
139
|
+
#### `#store!`, `#cache!`
|
140
|
+
|
141
|
+
In Shrine you store and cache files by instantiating it with a corresponding
|
142
|
+
storage, and calling `#upload`:
|
143
|
+
|
144
|
+
```rb
|
145
|
+
ImageUploader.new(:cache).upload(file)
|
146
|
+
ImageUploader.new(:store).upload(file)
|
147
|
+
```
|
148
|
+
|
149
|
+
Note that in Shrine you cannot pass in a path to the file, you always have to
|
150
|
+
pass an IO-like object, which is required to respond to: `#read(*args)`,
|
151
|
+
`#size`, `#eof?`, `#rewind` and `#close`.
|
152
|
+
|
153
|
+
#### `#retrieve_from_store!` and `#retrieve_from_cache!`
|
154
|
+
|
155
|
+
In Shrine you simply call `#download` on the uploaded file:
|
156
|
+
|
157
|
+
```rb
|
158
|
+
uploaded_file = ImageUploader.new(:store).upload(file)
|
159
|
+
uploaded_file.download #=> #<Tempfile>
|
160
|
+
```
|
161
|
+
|
162
|
+
#### `#url`
|
163
|
+
|
164
|
+
In Shrine you call `#url` on uploaded files:
|
165
|
+
|
166
|
+
```rb
|
167
|
+
user.avatar #=> #<Shrine::UploadedFile>
|
168
|
+
user.avatar.url #=> "/uploads/398454ujedfggf.jpg"
|
169
|
+
```
|
170
|
+
|
171
|
+
#### `#identifier`
|
172
|
+
|
173
|
+
This method corresponds to `#original_filename` on the uploaded file:
|
174
|
+
|
175
|
+
```rb
|
176
|
+
user.avatar #=> #<Shrine::UploadedFile>
|
177
|
+
user.avatar.original_filename #=> "avatar.jpg"
|
178
|
+
```
|
179
|
+
|
180
|
+
#### `#store_dir`, `#cache_dir`
|
181
|
+
|
182
|
+
Shrine here provides a `#generate_location` method, which is triggered for all
|
183
|
+
storages:
|
184
|
+
|
185
|
+
```rb
|
186
|
+
class ImageUploader < Shrine
|
187
|
+
def generate_location(io, context)
|
188
|
+
case storage_key
|
189
|
+
when :cache then "..."
|
190
|
+
when :store then "..."
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
```
|
195
|
+
|
196
|
+
The `context` variable holds the additional data, like the attacment name and
|
197
|
+
the record instance. You might also want to use the `pretty_location` plugin
|
198
|
+
for automatically generating an organized folder structure.
|
199
|
+
|
200
|
+
#### `#default_url`
|
201
|
+
|
202
|
+
Similarly to CarrierWave, you also provide default URLs be overriding the
|
203
|
+
method:
|
204
|
+
|
205
|
+
```rb
|
206
|
+
class ImageUploader < Shrine
|
207
|
+
def default_url(context)
|
208
|
+
# ...
|
209
|
+
end
|
210
|
+
end
|
211
|
+
```
|
212
|
+
|
213
|
+
The `context` variable holds the name of the attachment, record instance and
|
214
|
+
in some cases the `:version`.
|
215
|
+
|
216
|
+
#### `#extension_white_list`, `#extension_black_list`
|
217
|
+
|
218
|
+
In Shrine extension whitelisting/blacklisting is a part of validations, and is
|
219
|
+
provided by the `validation_helpers` plugin:
|
220
|
+
|
221
|
+
```rb
|
222
|
+
class ImageUploader < Shrine
|
223
|
+
plugin :validation_helpers
|
224
|
+
|
225
|
+
Attacher.validate do
|
226
|
+
validate_extension_inclusion [/jpe?g/, 'png'] # whitelist
|
227
|
+
validate_extension_exclusion ['php'] # blacklist
|
228
|
+
end
|
229
|
+
end
|
230
|
+
```
|
231
|
+
|
232
|
+
#### `#blacklist_mime_type_pattern`, `#whitelist_mime_type_pattern`
|
233
|
+
|
234
|
+
In Shrine MIME type whitelisting/blacklisting is part of validations, and is
|
235
|
+
provided by the `validation_helpers` plugin:
|
236
|
+
|
237
|
+
```rb
|
238
|
+
class ImageUploader < Shrine
|
239
|
+
plugin :validation_helpers
|
240
|
+
|
241
|
+
Attacher.validate do
|
242
|
+
validate_mime_type_inclusion [/image/] # whitelist
|
243
|
+
validate_mime_type_exclusion [/video/] # blacklist
|
244
|
+
end
|
245
|
+
end
|
246
|
+
```
|
247
|
+
|
248
|
+
#### `#size_range`
|
249
|
+
|
250
|
+
In Shrine file size validations are typically done using the
|
251
|
+
`validation_helpers` plugin:
|
252
|
+
|
253
|
+
|
254
|
+
```rb
|
255
|
+
class ImageUploader < Shrine
|
256
|
+
plugin :validation_helpers
|
257
|
+
|
258
|
+
Attacher.validate do
|
259
|
+
validate_min_size 0
|
260
|
+
validate_max_size 5*1024*1024 # 5 MB
|
261
|
+
end
|
262
|
+
end
|
263
|
+
```
|
264
|
+
|
265
|
+
#### `#recreate_versions!`
|
266
|
+
|
267
|
+
Shrine doesn't provide an automatic mechanism for recreating versions, because
|
268
|
+
that is very individual for different situations. For example, sometimes you want to
|
269
|
+
regenerate all versions and sometimes just one. However, I wrote a guide
|
270
|
+
"[Regenerating versions]" that should help you out with that.
|
271
|
+
|
272
|
+
### Models
|
273
|
+
|
274
|
+
The only thing that Shrine requires from your models is a `<attachment>_data`
|
275
|
+
column (e.g. if your attachment is "avatar", you need the `avatar_data` column).
|
276
|
+
|
277
|
+
#### `.mount_uploader`
|
278
|
+
|
279
|
+
In Shrine you make include attachment modules directly:
|
280
|
+
|
281
|
+
```rb
|
282
|
+
Shrine.plugin :sequel
|
283
|
+
```
|
284
|
+
```rb
|
285
|
+
class User < Sequel::Model
|
286
|
+
include ImageUploader[:avatar]
|
287
|
+
end
|
288
|
+
```
|
289
|
+
|
290
|
+
#### `#<attachment>=`
|
291
|
+
|
292
|
+
The attachment module adds an attachment setter:
|
293
|
+
|
294
|
+
```rb
|
295
|
+
user.avatar = File.open("avatar.jpg")
|
296
|
+
```
|
297
|
+
|
298
|
+
Note that unlike CarrierWave, you cannot pass in file paths, the input needs to
|
299
|
+
be an IO-like object.
|
300
|
+
|
301
|
+
#### `#<attachment>`
|
302
|
+
|
303
|
+
CarrierWave returns the uploader, but Shrine returns a `Shrine::UploadedFile`,
|
304
|
+
a representation of the file uploaded to the storage:
|
305
|
+
|
306
|
+
```rb
|
307
|
+
user.avatar #=> #<Shrine::UploadedFile>
|
308
|
+
user.avatar.methods #=> [:url, :download, :read, :exists?, :delete, ...]
|
309
|
+
```
|
310
|
+
|
311
|
+
If attachment is missing, nil is returned.
|
312
|
+
|
313
|
+
#### `#<attachment>_url`
|
314
|
+
|
315
|
+
This method is simply a shorthand for "if attachment is present, call `#url`
|
316
|
+
on it, otherwise return nil":
|
317
|
+
|
318
|
+
```rb
|
319
|
+
user.avatar_url #=> nil
|
320
|
+
user.avatar = File.open("avatar.jpg")
|
321
|
+
user.avatar_url #=> "/uploads/ksdf934rt.jpg"
|
322
|
+
```
|
323
|
+
|
324
|
+
The `versions` plugin extends this method to also accept a version name as the
|
325
|
+
argument (`user.avatar_url(:thumb)`).
|
326
|
+
|
327
|
+
#### `#<attachment>_cache`
|
328
|
+
|
329
|
+
Shrine doesn't provide this method, instead it expects to recieve the
|
330
|
+
attachment through the accessor, you can assign it `<attachment>_data`:
|
331
|
+
|
332
|
+
```erb
|
333
|
+
<%= form_for @user do |f| %>
|
334
|
+
<%= f.hidden_field :avatar, value: @user.avatar_data %>
|
335
|
+
<%= f.file_field :avatar %>
|
336
|
+
<% end %>
|
337
|
+
```
|
338
|
+
|
339
|
+
You might also want to look at the `cached_attachment_data` plugin.
|
340
|
+
|
341
|
+
#### `#remote_<attachment>_url`
|
342
|
+
|
343
|
+
In Shrine this method is provided by the `remote_url` plugin.
|
344
|
+
|
345
|
+
#### `#remove_<attachment>`
|
346
|
+
|
347
|
+
In Shrine this method is provided by the `remove_attachment` plugin.
|
348
|
+
|
349
|
+
### Configuration
|
350
|
+
|
351
|
+
This section walks through various configuration options in CarrierWave, and
|
352
|
+
shows what are Shrine's equivalents.
|
353
|
+
|
354
|
+
#### `root`, `base_path`, `permissions`, `directory_permissions`
|
355
|
+
|
356
|
+
In Shrine these are configured on the FileSystem storage directly.
|
357
|
+
|
358
|
+
#### `storage`, `storage_engines`
|
359
|
+
|
360
|
+
As mentioned before, in Shrine you register storages through `Shrine.storages`,
|
361
|
+
and the attachment storages will automatically be `:cache` and `:store`, but
|
362
|
+
you can change this with the `default_storage` plugin.
|
363
|
+
|
364
|
+
#### `fog_*`
|
365
|
+
|
366
|
+
These options will be set on the soon-to-be-released Fog storage for Shrine.
|
367
|
+
|
368
|
+
#### `delete_tmp_file_after_storage`, `remove_previously_stored_file_after_update`
|
369
|
+
|
370
|
+
By default Shrine deletes cached and replaced files, but you can choose to keep
|
371
|
+
those files by loading the `keep_files` plugin:
|
372
|
+
|
373
|
+
```rb
|
374
|
+
Shrine.plugin :keep_files, cached: true, replaced: true
|
375
|
+
```
|
376
|
+
|
377
|
+
#### `move_to_cache`, `move_to_store`
|
378
|
+
|
379
|
+
Shrine brings this functionality through the `moving` plugin.
|
380
|
+
|
381
|
+
```rb
|
382
|
+
Shrine.plugin :moving, storages: [:cache]
|
383
|
+
```
|
384
|
+
|
385
|
+
#### `validate_integrity`, `ignore_integrity_errors`
|
386
|
+
|
387
|
+
Shrine does this with validation, which are best done with the
|
388
|
+
`validation_helpers` plugin:
|
389
|
+
|
390
|
+
```rb
|
391
|
+
class ImageUploader < Shrine
|
392
|
+
plugin :validation_helpers
|
393
|
+
|
394
|
+
Attacher.validate do
|
395
|
+
# Evaluated inside an instance of Shrine::Attacher.
|
396
|
+
if record.guest?
|
397
|
+
validate_max_size 2*1024*1024, message: "is too large (max is 2 MB)"
|
398
|
+
validate_mime_type_inclusion ["image/jpg", "image/png", "image/gif"]
|
399
|
+
end
|
400
|
+
end
|
401
|
+
end
|
402
|
+
```
|
403
|
+
|
404
|
+
#### `validate_download`, `ignore_download_errors`
|
405
|
+
|
406
|
+
Shrine's `remote_url` plugin always rescues download errors and transforms
|
407
|
+
them to validation errors.
|
408
|
+
|
409
|
+
#### `validate_processing`, `ignore_processing_errors`
|
410
|
+
|
411
|
+
Shrine doesn't offer any built-in ways of rescuing processing errors, because
|
412
|
+
it completely depends on how you do your processing. You can easily add your
|
413
|
+
own rescuing:
|
414
|
+
|
415
|
+
```rb
|
416
|
+
class ImageUploader < Shrine
|
417
|
+
def process(io, context)
|
418
|
+
# processing
|
419
|
+
rescue SomeProcessingError
|
420
|
+
# handling
|
421
|
+
end
|
422
|
+
end
|
423
|
+
```
|
424
|
+
|
425
|
+
#### `enable_processing`
|
426
|
+
|
427
|
+
You can just do conditionals inside if `Shrine#process`.
|
428
|
+
|
429
|
+
#### `ensure_multipart_form`
|
430
|
+
|
431
|
+
No equivalent, it depends on your application whether you need the form to be
|
432
|
+
multipart or not.
|
433
|
+
|
434
|
+
[image_processing]: https://github.com/janko-m/image_processing
|
435
|
+
[example app]: https://github.com/janko-m/shrine-example
|
436
|
+
[Regenerating versions]: http://shrinerb.com/rdoc/files/doc/regenerating_versions_md.html
|