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.

Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +16 -0
  3. data/LICENSE.txt +1 -1
  4. data/README.md +7 -2
  5. data/doc/advantages.md +29 -12
  6. data/doc/carrierwave.md +54 -22
  7. data/doc/changing_derivatives.md +39 -39
  8. data/doc/getting_started.md +63 -58
  9. data/doc/multiple_files.md +5 -3
  10. data/doc/paperclip.md +92 -33
  11. data/doc/plugins/activerecord.md +1 -1
  12. data/doc/plugins/data_uri.md +2 -2
  13. data/doc/plugins/derivation_endpoint.md +26 -28
  14. data/doc/plugins/derivatives.md +170 -142
  15. data/doc/plugins/determine_mime_type.md +2 -2
  16. data/doc/plugins/infer_extension.md +2 -2
  17. data/doc/plugins/instrumentation.md +1 -1
  18. data/doc/plugins/metadata_attributes.md +21 -10
  19. data/doc/plugins/persistence.md +1 -0
  20. data/doc/plugins/refresh_metadata.md +5 -4
  21. data/doc/plugins/remote_url.md +2 -2
  22. data/doc/plugins/signature.md +11 -2
  23. data/doc/plugins/store_dimensions.md +2 -2
  24. data/doc/plugins/upload_endpoint.md +7 -11
  25. data/doc/plugins/validation_helpers.md +3 -3
  26. data/doc/processing.md +5 -5
  27. data/doc/refile.md +30 -9
  28. data/doc/release_notes/2.19.0.md +1 -1
  29. data/doc/release_notes/3.0.1.md +4 -0
  30. data/doc/release_notes/3.1.0.md +73 -0
  31. data/doc/securing_uploads.md +1 -1
  32. data/doc/storage/file_system.md +1 -1
  33. data/doc/storage/s3.md +1 -5
  34. data/doc/upgrading_to_3.md +4 -2
  35. data/doc/validation.md +3 -2
  36. data/lib/shrine.rb +1 -2
  37. data/lib/shrine/attacher.rb +4 -4
  38. data/lib/shrine/attachment.rb +3 -3
  39. data/lib/shrine/plugins/add_metadata.rb +1 -5
  40. data/lib/shrine/plugins/default_storage.rb +6 -6
  41. data/lib/shrine/plugins/derivatives.rb +4 -3
  42. data/lib/shrine/plugins/signature.rb +7 -6
  43. data/lib/shrine/plugins/store_dimensions.rb +18 -9
  44. data/lib/shrine/uploaded_file.rb +0 -1
  45. data/lib/shrine/version.rb +2 -2
  46. metadata +3 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0b327565465d4140206d1f88433647e7959b6c56ecbdea7d433f1aa5eb01825d
4
- data.tar.gz: c19fb7f15299b1d061325f8f83e790f44481456fbc9730d4a909923193dde1a3
3
+ metadata.gz: 30bd30989579217202b2c51b9a00abe778af7cbab75fc9df78052bc074ce9405
4
+ data.tar.gz: 5c718df903c203e06ea44afa9c9017fa2cf01a8924c99e86a87be52f52ce0233
5
5
  SHA512:
6
- metadata.gz: 897bbe8787b3a1f7e59db3e6beebbc91b32ec5e4c19cd832029e05205425c12d837bf8475f21949c23a6c805504da45a0937de0d3dc9f50d3d35921b5f6a7901
7
- data.tar.gz: 995b0ada0e5bdb2c4e198304d913f6cfe22d8814328d58bf559490ea572ac3d5555f3eb15fce898ae423ff54f76ba3bcbbeb7f6e05470ddca8acee37ee675455
6
+ metadata.gz: 27f896211caba27686d5988750ce214ec0b31e70e9bbcf8a7d325952a5eee2e4c3293d539bb3074d4384964723bda09edd1acfcdcd387d82a4ef7373ff5787f0
7
+ data.tar.gz: 3d06d57d2eb1fee1cada71dfa4092a23c4b0bf4d5df8cf76e2fbf2eb4eaf5c9477f333ef241772d917456ebfb3067ad0ce7adc6becc49e15c9129720842cd5b3
@@ -1,3 +1,19 @@
1
+ ## 3.1.0 (2019-11-15) [[release notes]](https://shrinerb.com/docs/release_notes/3.1.0)
2
+
3
+ * `default_storage` – Coerce storage key to symbol in `Attacher#cache_key` & `Attacher#store_key` (@janko)
4
+
5
+ * `core` – Coerce storage key to symbol in `Attacher#cache_key` & `Attacher#store_key` (@janko)
6
+
7
+ * `add_metadata` – Define metadata methods only for the target uploader class (@janko)
8
+
9
+ * `derivatives` – Add `:storage` option to `Attacher#create_derivatives` (@janko)
10
+
11
+ * `store_dimensions` – Propagate exceptions on loading `ruby-vips` in `:vips` analyzer (@janko)
12
+
13
+ * `signature` – Allow skipping rewinding by passing `rewind: false` to `Shrine.signature` (@janko)
14
+
15
+ * `derivatives` – Add `Attacher.derivatives` alias for `Attacher.derivatives_processor` (@janko)
16
+
1
17
  ## 3.0.1 (2019-10-17) [[release notes]](https://shrinerb.com/docs/release_notes/3.0.1)
2
18
 
3
19
  * `metadata_attributes` – Fix exception being raised when there is no attached file (@janko)
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2015-2017 Janko Marohnić
3
+ Copyright (c) 2015-2019 Janko Marohnić
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # [Shrine]
2
2
 
3
+ <img src="https://shrinerb.com/img/logo.png" width="100" alt="Shrine logo: a red paperclip" align="right" />
4
+
3
5
  Shrine is a toolkit for handling file attachments in Ruby applications. Some highlights:
4
6
 
5
7
  * **Modular design** – the [plugin system] allows you to load only the functionality you need
@@ -12,7 +14,9 @@ Shrine is a toolkit for handling file attachments in Ruby applications. Some hig
12
14
  * **Resumable uploads** – make large file uploads [resumable][resumable upload] on [S3][uppy-s3_multipart] or [tus][tus-ruby-server]
13
15
  * **Background jobs** – built-in support for [background processing][backgrounding] that supports [any backgrounding library][Backgrounding Libraries]
14
16
 
15
- Please follow along with the **[Getting Started guide]**.
17
+ If you're curious how it compares to other file attachment libraries, see the
18
+ [Advantages of Shrine]. Otherwise, follow along with the **[Getting Started
19
+ guide]**.
16
20
 
17
21
  ## Links
18
22
 
@@ -52,7 +56,7 @@ Shrine.plugin :restore_cached_data # extracts metadata for assigned cached fi
52
56
  Next, add the `<name>_data` column to the table you want to attach files to. For
53
57
  an "image" attachment on a `photos` table this would be an `image_data` column:
54
58
 
55
- ```sh
59
+ ```
56
60
  $ rails generate migration add_image_data_to_photos image_data:text
57
61
  ```
58
62
 
@@ -133,6 +137,7 @@ mailing lists is expected to follow the [Shrine code of conduct][CoC].
133
137
  The gem is available as open source under the terms of the [MIT License].
134
138
 
135
139
  [Shrine]: https://shrinerb.com
140
+ [Advantages of Shrine]: https://shrinerb.com/docs/advantages
136
141
  [plugin system]: https://shrinerb.com/docs/getting-started#plugin-system
137
142
  [Retrieving Uploads]: https://shrinerb.com/docs/retrieving-uploads
138
143
  [FileSystem]: https://shrinerb.com/docs/storage/file-system
@@ -171,7 +171,7 @@ thumbnails during attachment:
171
171
 
172
172
  ```rb
173
173
  class ImageUploader < Shrine
174
- Attacher.derivatives_processor do |original|
174
+ Attacher.derivatives do |original|
175
175
  magick = ImageProcessing::MiniMagick.source(original)
176
176
 
177
177
  {
@@ -261,7 +261,7 @@ gem "streamio-ffmpeg"
261
261
  ```
262
262
  ```rb
263
263
  class VideoUploader < Shrine
264
- Attacher.derivatives_processor do |original|
264
+ Attacher.derivatives do |original|
265
265
  transcoded = Tempfile.new ["transcoded", ".mp4"]
266
266
  screenshot = Tempfile.new ["screenshot", ".jpg"]
267
267
 
@@ -281,7 +281,7 @@ movie.video(:transcoded) #=> #<Shrine::UploadedFile id="7481d6.mp4" ...>
281
281
  movie.video(:screenshot) #=> #<Shrine::UploadedFile id="8f3136.jpg" ...>
282
282
  ```
283
283
 
284
- ## Metadata & Validation
284
+ ## Metadata
285
285
 
286
286
  Shrine automatically [extracts metadata][metadata] from each uploaded file,
287
287
  including derivatives like image thumbnails, and saves them into the database
@@ -289,6 +289,17 @@ column. In addition to filename, filesize, and MIME type that are extracted by
289
289
  default, you can also extract [image dimensions][store_dimensions], or your own
290
290
  [custom metadata][add_metadata].
291
291
 
292
+ ```rb
293
+ class ImageUploader < Shrine
294
+ plugin :determine_mime_type # mime_type
295
+ plugin :store_dimensions # width & height
296
+
297
+ add_metadata :resolution do |io|
298
+ image = MiniMagick::Image.new(io.path)
299
+ image.resolution
300
+ end
301
+ end
302
+ ```
292
303
  ```rb
293
304
  photo.image.metadata #=>
294
305
  # {
@@ -297,23 +308,30 @@ photo.image.metadata #=>
297
308
  # "mime_type" => "image/jpeg",
298
309
  # "width" => 600,
299
310
  # "height" => 400,
311
+ # "resolution" => [72, 72],
300
312
  # ...
301
313
  # }
302
314
  ```
303
315
 
304
- For common metadata you can use the built-in [validators][validation_helpers],
305
- but you can also [validate any custom metadata][custom validations].
316
+ ## Validation
317
+
318
+ For file validations there are [built-in validators][validation_helpers], but
319
+ you can also just use plain Ruby code:
306
320
 
307
321
  ```rb
308
- class DocumentUploader < Shrine
322
+ class ImageUploader < Shrine
323
+ plugin :validation_helpers
324
+
309
325
  Attacher.validate do
310
- # validation macros
311
326
  validate_max_size 10*1024*1024
312
- validate_mime_type %W[application/pdf]
327
+ validate_extension %w[jpg jpeg png webp]
328
+
329
+ if validate_mime_type %W[image/jpeg image/png image/webp]
330
+ validate_max_dimensions [5000, 5000]
313
331
 
314
- # custom validations
315
- if file["page_count"] > 30
316
- errors << "must not have more than 30 pages"
332
+ unless ImageProcessing::MiniMagick.valid_image?(file.download.path)
333
+ error << "seems to be corrupted"
334
+ end
317
335
  end
318
336
  end
319
337
  end
@@ -432,7 +450,6 @@ on top of Rack, so that they can be used with any Ruby web framework.
432
450
  [backgrounding libraries]: https://github.com/shrinerb/shrine/wiki/Backgrounding-Libraries
433
451
  [Down streaming]: https://github.com/janko/down#streaming
434
452
  [validation_helpers]: https://shrinerb.com/docs/plugins/validation_helpers
435
- [custom validations]: https://shrinerb.com/docs/validation#custom-validations
436
453
  [derivatives]: https://shrinerb.com/docs/plugins/derivatives
437
454
  [derivation_endpoint]: https://shrinerb.com/docs/plugins/derivation_endpoint
438
455
  [libvips performance]: https://github.com/libvips/libvips/wiki/Speed-and-memory-use#results
@@ -6,7 +6,7 @@ This guide is aimed at helping CarrierWave 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 CarrierWave and Shrine
9
- 2. Instructions how to migrate and existing app that uses CarrierWave to Shrine
9
+ 2. Instructions how to migrate an existing app that uses CarrierWave to Shrine
10
10
  3. Extensive reference of CarrierWave's interface with Shrine equivalents
11
11
 
12
12
  ## Overview
@@ -159,7 +159,7 @@ require "image_processing/mini_magick"
159
159
  class ImageUploader < Shrine
160
160
  plugin :derivatives
161
161
 
162
- Attacher.derivatives_processor do |original|
162
+ Attacher.derivatives do |original|
163
163
  magick = ImageProcessing::MiniMagick.source(original)
164
164
 
165
165
  {
@@ -268,18 +268,24 @@ Files] guide explains this setup in more detail.
268
268
  ## Migrating from CarrierWave
269
269
 
270
270
  You have an existing app using CarrierWave and you want to transfer it to
271
- Shrine. Let's assume we have a `Photo` model with the "image" attachment. First
272
- we need to create the `image_data` column for Shrine:
271
+ Shrine. Let's assume we have a `Photo` model with the "image" attachment.
272
+
273
+ ### 1. Add Shrine column
274
+
275
+ First we need to create the `image_data` column for Shrine:
273
276
 
274
277
  ```rb
275
278
  add_column :photos, :image_data, :text # or :json or :jsonb if supported
276
279
  ```
277
280
 
278
- Afterwards we need to make new uploads write to the `image_data` column. This
279
- can be done by including the below module to all models that have CarrierWave
280
- attachments:
281
+ ### 2. Dual write
282
+
283
+ Next, we need to make new CarrierWave attachments write to the
284
+ `image_data` column. This can be done by including the below module to all
285
+ models that have CarrierWave attachments:
281
286
 
282
287
  ```rb
288
+ # config/initializers/shrine.rb (Rails)
283
289
  require "shrine"
284
290
 
285
291
  Shrine.storages = {
@@ -289,8 +295,7 @@ Shrine.storages = {
289
295
 
290
296
  Shrine.plugin :model
291
297
  Shrine.plugin :derivatives
292
- ```
293
- ```rb
298
+
294
299
  module CarrierwaveShrineSynchronization
295
300
  def self.included(model)
296
301
  model.before_save do
@@ -302,13 +307,13 @@ module CarrierwaveShrineSynchronization
302
307
 
303
308
  def write_shrine_data(name)
304
309
  uploader = send(name)
305
- attacher = Shrine::Attacher.form_model(self, name)
310
+ attacher = Shrine::Attacher.from_model(self, name)
306
311
 
307
312
  if read_attribute(name).present?
308
313
  attacher.set shrine_file(uploader)
309
314
 
310
- uploader.versions.each do |name, version|
311
- attacher.merge_derivatives(name => shrine_file(version))
315
+ uploader.versions.each do |version_name, version|
316
+ attacher.merge_derivatives(version_name => shrine_file(version))
312
317
  end
313
318
  else
314
319
  attacher.set nil
@@ -340,20 +345,27 @@ end
340
345
  ```
341
346
 
342
347
  After you deploy this code, the `image_data` column should now be successfully
343
- synchronized with new attachments. Next step is to run a script which writes
344
- all existing CarrierWave attachments to `image_data`:
348
+ synchronized with new attachments.
349
+
350
+ ### 3. Data migration
351
+
352
+ Next step is to run a script which writes all existing CarrierWave attachments
353
+ to `image_data`:
345
354
 
346
355
  ```rb
347
356
  Photo.find_each do |photo|
348
- Photo.uploaders.each_key { |name| photo.write_shrine_data(name) }
357
+ photo.write_shrine_data(:image)
349
358
  photo.save!
350
359
  end
351
360
  ```
352
361
 
362
+ ### 4. Rewrite code
363
+
353
364
  Now you should be able to rewrite your application so that it uses Shrine
354
- instead of CarrierWave, using equivalent Shrine storages. For help with
355
- translating the code from CarrierWave to Shrine, you can consult the reference
356
- below.
365
+ instead of CarrierWave (you can consult the reference in the next section). You
366
+ can remove the `CarrierwaveShrineSynchronization` module as well.
367
+
368
+ ### 5. Backill metadata
357
369
 
358
370
  You'll notice that Shrine metadata will be absent from the migrated files'
359
371
  data. You can run a script that will fill in any missing metadata defined in
@@ -363,11 +375,20 @@ your Shrine uploader:
363
375
  Shrine.plugin :refresh_metadata
364
376
 
365
377
  Photo.find_each do |photo|
366
- photo.image_attacher.refresh_metadata!
367
- photo.save
378
+ attacher = photo.image_attacher
379
+ attacher.refresh_metadata!
380
+ attacher.atomic_persist
368
381
  end
369
382
  ```
370
383
 
384
+ ### 6. Remove CarrierWave column
385
+
386
+ If everything is looking good, we can remove the CarrierWave column:
387
+
388
+ ```rb
389
+ remove_column :photos, :image
390
+ ```
391
+
371
392
  ## CarrierWave to Shrine direct mapping
372
393
 
373
394
  ### `CarrierWave::Uploader::Base`
@@ -395,7 +416,7 @@ Processing is defined by using the `derivatives` plugin:
395
416
  class ImageUploader < Shrine
396
417
  plugin :derivatives
397
418
 
398
- Attacher.derivatives_processor do |original|
419
+ Attacher.derivatives do |original|
399
420
  magick = ImageProcessing::MiniMagick.source(image)
400
421
 
401
422
  {
@@ -499,7 +520,7 @@ class ImageUploader < Shrine
499
520
  end
500
521
  ```
501
522
 
502
- #### `#blacklist_mime_type_pattern`, `#whitelist_mime_type_pattern`, `#content_type_whitelist`, `#content_type_blacklist`
523
+ #### `#content_type_whitelist`, `#content_type_blacklist`
503
524
 
504
525
  In Shrine, MIME type whitelisting/blacklisting is part of validations, and is
505
526
  provided by the `validation_helpers` plugin, though it doesn't support regexes:
@@ -515,6 +536,17 @@ class ImageUploader < Shrine
515
536
  end
516
537
  ```
517
538
 
539
+ Make sure to also load the `determine_mime_type` plugin to detect MIME type
540
+ from file content.
541
+
542
+ ```rb
543
+ # Gemfile
544
+ gem "mimemagic"
545
+ ```
546
+ ```rb
547
+ Shrine.plugin :determine_mime_type, analyzer: :mimemagic
548
+ ```
549
+
518
550
  #### `#size_range`
519
551
 
520
552
  In Shrine file size validations are typically done using the
@@ -42,7 +42,7 @@ gem "image_processing", "~> 1.8"
42
42
  require "image_processing/mini_magick"
43
43
 
44
44
  class ImageUploader < Shrine
45
- Attacher.derivatives_processor do |original|
45
+ Attacher.derivatives do |original|
46
46
  magick = ImageProcessing::MiniMagick.source(original)
47
47
 
48
48
  # generate the thumbnails you want here
@@ -93,16 +93,16 @@ now you want to reprocess them for existing attachments.*
93
93
  Let's assume we've made the following change and have deployed it to production:
94
94
 
95
95
  ```diff
96
- Attacher.derivatives_processor do |original|
97
- magick = ImageProcessing::MiniMagick.source(original)
96
+ Attacher.derivatives do |original|
97
+ magick = ImageProcessing::MiniMagick.source(original)
98
98
  + .saver(quality: 85)
99
99
 
100
- {
101
- small: magick.resize_to_limit!(300, 300),
102
- medium: magick.resize_to_limit!(500, 500),
103
- large: magick.resize_to_limit!(800, 800),
104
- }
105
- end
100
+ {
101
+ small: magick.resize_to_limit!(300, 300),
102
+ medium: magick.resize_to_limit!(500, 500),
103
+ large: magick.resize_to_limit!(800, 800),
104
+ }
105
+ end
106
106
  ```
107
107
 
108
108
  We can now run the following script to reprocess derivatives for all existing
@@ -139,16 +139,16 @@ you want to reprocess them for existing attachments.*
139
139
  Let's assume we've made a following change and have deployed it to production:
140
140
 
141
141
  ```diff
142
- Attacher.derivatives_processor do |original|
143
- magick = ImageProcessing::MiniMagick.source(original)
144
-
145
- {
146
- small: magick.resize_to_limit!(300, 300),
147
- - medium: magick.resize_to_limit!(500, 500),
148
- + medium: magick.resize_to_limit!(600, 600),
149
- large: magick.resize_to_limit!(800, 800),
150
- }
151
- end
142
+ Attacher.derivatives do |original|
143
+ magick = ImageProcessing::MiniMagick.source(original)
144
+
145
+ {
146
+ small: magick.resize_to_limit!(300, 300),
147
+ - medium: magick.resize_to_limit!(500, 500),
148
+ + medium: magick.resize_to_limit!(600, 600),
149
+ large: magick.resize_to_limit!(800, 800),
150
+ }
151
+ end
152
152
  ```
153
153
 
154
154
  We can now run the following script to reprocess the derivative for all
@@ -189,16 +189,16 @@ you want to add it to existing attachments.*
189
189
  Let's assume we've made a following change and have deployed it to production:
190
190
 
191
191
  ```diff
192
- Attacher.derivatives_processor do |original|
193
- magick = ImageProcessing::MiniMagick.source(original)
194
-
195
- {
196
- + square: magick.resize_to_fill!(150, 150),
197
- small: magick.resize_to_limit!(300, 300),
198
- medium: magick.resize_to_limit!(600, 600),
199
- large: magick.resize_to_limit!(800, 800),
200
- }
201
- end
192
+ Attacher.derivatives do |original|
193
+ magick = ImageProcessing::MiniMagick.source(original)
194
+
195
+ {
196
+ + square: magick.resize_to_fill!(150, 150),
197
+ small: magick.resize_to_limit!(300, 300),
198
+ medium: magick.resize_to_limit!(600, 600),
199
+ large: magick.resize_to_limit!(800, 800),
200
+ }
201
+ end
202
202
  ```
203
203
 
204
204
  We can now run following script to add the new derivative for all existing
@@ -239,16 +239,16 @@ existing attachments.*
239
239
  Let's assume we've made the following change and have deployed it to production:
240
240
 
241
241
  ```diff
242
- Attacher.derivatives_processor do |original|
243
- magick = ImageProcessing::MiniMagick.source(original)
244
-
245
- {
246
- - square: magick.resize_to_fill!(150, 150),
247
- small: magick.resize_to_limit!(300, 300),
248
- medium: magick.resize_to_limit!(600, 600),
249
- large: magick.resize_to_limit!(800, 800),
250
- }
251
- end
242
+ Attacher.derivatives do |original|
243
+ magick = ImageProcessing::MiniMagick.source(original)
244
+
245
+ {
246
+ - square: magick.resize_to_fill!(150, 150),
247
+ small: magick.resize_to_limit!(300, 300),
248
+ medium: magick.resize_to_limit!(600, 600),
249
+ large: magick.resize_to_limit!(800, 800),
250
+ }
251
+ end
252
252
  ```
253
253
 
254
254
  We can now run following script to remove the unused derivative for all
@@ -50,7 +50,7 @@ class AddImageDataToPhotos < ActiveRecord::Migration
50
50
  end
51
51
  ```
52
52
  <!--Rails-->
53
- ```sh
53
+ ```
54
54
  $ rails generate migration add_image_data_to_photos image_data:text
55
55
  ```
56
56
  <!--END_DOCUSAURUS_CODE_TABS-->
@@ -186,8 +186,8 @@ s3_options = {
186
186
  }
187
187
 
188
188
  Shrine.storages = {
189
- cache: Shrine::Storage::S3.new(prefix: "cache", **s3_options),
190
- store: Shrine::Storage::S3.new(**s3_options),
189
+ cache: Shrine::Storage::S3.new(prefix: "cache", **s3_options), # temporary
190
+ store: Shrine::Storage::S3.new(**s3_options), # permanent
191
191
  }
192
192
  ```
193
193
 
@@ -254,15 +254,17 @@ uploader.upload(io, upload_options: { acl: "public-read" }) # add options to Sto
254
254
 
255
255
  Shrine is able to upload any IO-like object that implement methods [`#read`],
256
256
  [`#rewind`], [`#eof?`] and [`#close`] whose behaviour matches the [`IO`] class.
257
- This includes built-in IO and IO-like objects like File, Tempfile and StringIO.
257
+ This includes but is not limited to the following objects:
258
258
 
259
- When a file is uploaded to a Rails app, in request params it will be
260
- represented by an `ActionDispatch::Http::UploadedFile` object, which is also an
261
- IO-like object accepted by Shrine. In other Rack applications the uploaded file
262
- will be represented as a Hash, but it can be converted into an IO-like object
263
- with the [`rack_file`][rack_file plugin] plugin.
264
-
265
- Here are some examples of various IO-like objects that can be uploaded:
259
+ * `File`
260
+ * `Tempfile`
261
+ * `StringIO`
262
+ * `ActionDispatch::Http::UploadedFile` (Rails form upload)
263
+ * `Shrine::RackFile` ([`rack_file`][rack_file plugin] plugin)
264
+ * `Shrine::DataFile` ([`data_uri`][data_uri plugin] plugin)
265
+ * `Shrine::UploadedFile`
266
+ * `Down::ChunkedIO` ([Down] gem)
267
+ * ...
266
268
 
267
269
  ```rb
268
270
  uploader.upload File.open("/path/to/file", binmode: true) # upload from disk
@@ -278,7 +280,15 @@ uploader.upload Shrine::UploadedFile.new(...) # upload from Shrine
278
280
 
279
281
  The `Shrine::UploadedFile` object represents the file that was uploaded to a
280
282
  storage, and it's what's returned from `Shrine#upload` or when retrieving a
281
- record [attachment]. It contains the following data:
283
+ record [attachment].
284
+
285
+ ```rb
286
+ uploader.upload(file) #=> #<Shrine::UploadedFile ...> (uploader)
287
+ photo.image #=> #<Shrine::UploadedFile ...> (attachment)
288
+ attacher.file #=> #<Shrine::UploadedFile ...> (attacher)
289
+ ```
290
+
291
+ An uploaded file object contains the following data:
282
292
 
283
293
  | Key | Description |
284
294
  | :------- | :---------- |
@@ -287,13 +297,12 @@ record [attachment]. It contains the following data:
287
297
  | `metadata` | file [metadata] that was extracted before upload |
288
298
 
289
299
  ```rb
290
- uploaded_file = uploader.upload(file)
291
300
  uploaded_file #=> #<Shrine::UploadedFile id="949sdjg834.jpg" storage=:store metadata={...}>
292
301
 
293
- uploaded_file.id # => "949sdjg834.jpg"
294
- uploaded_file.storage_key # => :store
295
- uploaded_file.storage # => #<Shrine::Storage::S3>
296
- uploaded_file.metadata # => {...}
302
+ uploaded_file.id #=> "949sdjg834.jpg"
303
+ uploaded_file.storage_key #=> :store
304
+ uploaded_file.storage #=> #<Shrine::Storage::S3>
305
+ uploaded_file.metadata #=> {...}
297
306
  ```
298
307
 
299
308
  It comes with many convenient methods that delegate to the storage:
@@ -341,7 +350,7 @@ The easiest way to attach files is with the `Shrine::Attachment` module:
341
350
  ```rb
342
351
  class Photo < Sequel::Model # ActiveRecord::Base
343
352
  include ImageUploader::Attachment.new(:image) #
344
- include ImageUploader::Attachment[:image] # use a preferred syntax
353
+ include ImageUploader::Attachment[:image] # use your preferred syntax
345
354
  include ImageUploader::Attachment(:image) #
346
355
  end
347
356
  ```
@@ -364,7 +373,7 @@ that attachments are deleted when the record is destroyed.
364
373
  photo.image #=> nil
365
374
 
366
375
  # the assigned file is cached to temporary storage and written to `image_data` column
367
- photo.image = File.open("waterfall.jpg")
376
+ photo.image = File.open("waterfall.jpg", "rb")
368
377
  photo.image #=> #<Shrine::UploadedFile ...>
369
378
  photo.image_url #=> "/uploads/cache/0sdfllasfi842.jpg"
370
379
  photo.image_data #=> '{"id":"0sdfllasfi842.jpg","storage":"cache","metadata":{...}}'
@@ -408,12 +417,10 @@ attacher.url # equivalent to `photo.image_url`
408
417
  ```
409
418
 
410
419
  The attacher is what drives attaching files to model instances; you can use it
411
- as a more explicit alternative to models' attachment interface, or simply when
412
- you need something that's not available through the attachment methods.
420
+ as a more explicit alternative to models' attachment interface, or when you
421
+ need something that's not available through the attachment methods.
413
422
 
414
- You can do things such as change the temporary and permanent storage the
415
- attacher uses, or upload files directly to permanent storage. See the [Using
416
- Attacher] guide for more details.
423
+ See [Using Attacher] guide for more details.
417
424
 
418
425
  ### Temporary storage
419
426
 
@@ -424,18 +431,18 @@ files go straight to permanent storage:
424
431
  ```rb
425
432
  Shrine.plugin :model, cache: false
426
433
  ```
427
- <!--DOCUSAURUS_CODE_TABS-->
428
- <!--Attachment-->
429
434
  ```rb
430
- photo.image = File.open("waterfall.jpg")
435
+ photo.image = File.open("waterfall.jpg", "rb")
431
436
  photo.image.storage_key #=> :store
432
437
  ```
433
- <!--Attacher-->
438
+
439
+ If you're using the attacher directly, you can just use `Attacher#attach`
440
+ instead of `Attacher#assign`:
441
+
434
442
  ```rb
435
- attacher.attach File.open("waterfall.jpg")
443
+ attacher.attach File.open("waterfall.jpg", "rb")
436
444
  attacher.file.storage_key #=> :store
437
445
  ```
438
- <!--END_DOCUSAURUS_CODE_TABS-->
439
446
 
440
447
  ## Plugin system
441
448
 
@@ -519,7 +526,7 @@ For image processing, it's recommended to use the **[ImageProcessing]** gem,
519
526
  which is a high-level wrapper for processing with
520
527
  [MiniMagick][ImageProcessing::MiniMagick] and [libvips][ImageProcessing::Vips].
521
528
 
522
- ```sh
529
+ ```
523
530
  $ brew install imagemagick vips
524
531
  ```
525
532
 
@@ -539,7 +546,7 @@ Shrine.plugin :derivatives
539
546
  require "image_processing/mini_magick"
540
547
 
541
548
  class ImageUploader < Shrine
542
- Attacher.derivatives_processor do |original|
549
+ Attacher.derivatives do |original|
543
550
  magick = ImageProcessing::MiniMagick.source(original)
544
551
 
545
552
  {
@@ -580,12 +587,9 @@ documentation and the [File Processing] guide.
580
587
  ### Processing on-the-fly
581
588
 
582
589
  On-the-fly processing is provided by the
583
- [`derivation_endpoint`][derivation_endpoint plugin] plugin. It comes with a
584
- [mountable][Mounting Endpoints] Rack app which applies processing on request
585
- and returns processed files.
586
-
587
- To set it up, we mount the Rack app in our router on a chosen path prefix,
588
- configure the plugin with a secret key and that path prefix, and define
590
+ [`derivation_endpoint`][derivation_endpoint plugin] plugin. To set it up, we
591
+ configure the plugin with a secret key and a path prefix, [mount][Mounting
592
+ Endpoints] its Rack app in our routes on the configured path prefix, and define
589
593
  processing we want to perform:
590
594
 
591
595
  ```rb
@@ -593,25 +597,24 @@ processing we want to perform:
593
597
  gem "image_processing", "~> 1.8"
594
598
  ```
595
599
  ```rb
596
- # config/routes.rb (Rails)
597
- Rails.application.routes.draw do
598
- # ...
599
- mount ImageUploader.derivation_endpoint => "/derivations/image"
600
+ # config/initializers/shrine.rb (Rails)
601
+ require "image_processing/mini_magick"
602
+
603
+ Shrine.plugin :derivation_endpoint,
604
+ secret_key: "<YOUR SECRET KEY>",
605
+ prefix: "derivations" # needs to match the mount point in routes
606
+
607
+ Shrine.derivation :thumbnail do |file, width, height|
608
+ ImageProcessing::MiniMagick
609
+ .source(file)
610
+ .resize_to_limit!(width.to_i, height.to_i)
600
611
  end
601
612
  ```
602
613
  ```rb
603
- require "image_processing/mini_magick"
604
-
605
- class ImageUploader < Shrine
606
- plugin :derivation_endpoint,
607
- secret_key: "<YOUR SECRET KEY>",
608
- prefix: "derivations/image" # needs to match the mount point in routes
609
-
610
- derivation :thumbnail do |file, width, height|
611
- ImageProcessing::MiniMagick
612
- .source(file)
613
- .resize_to_limit!(width.to_i, height.to_i)
614
- end
614
+ # config/routes.rb (Rails)
615
+ Rails.application.routes.draw do
616
+ # ...
617
+ mount Shrine.derivation_endpoint => "/derivations"
615
618
  end
616
619
  ```
617
620
 
@@ -620,7 +623,7 @@ processing:
620
623
 
621
624
  ```rb
622
625
  photo.image.derivation_url(:thumbnail, 600, 400)
623
- #=> "/derivations/image/thumbnail/600/400/eyJpZCI6ImZvbyIsInN0b3JhZ2UiOiJzdG9yZSJ9?signature=..."
626
+ #=> "/derivations/thumbnail/600/400/eyJpZCI6ImZvbyIsInN0b3JhZ2UiOiJzdG9yZSJ9?signature=..."
624
627
  ```
625
628
 
626
629
  The on-the-fly processing feature is highly customizable, see the
@@ -675,7 +678,7 @@ class ImageUploader < Shrine
675
678
  end
676
679
  end
677
680
  ```
678
- ```plaintext
681
+ ```
679
682
  uploads/
680
683
  photos/
681
684
  originals/
@@ -906,7 +909,7 @@ uploaded_file.exists?
906
909
  uploaded_file.download
907
910
  uploaded_file.delete
908
911
  ```
909
- ```plaintext
912
+ ```
910
913
  Metadata (32ms) – {:storage=>:store, :io=>StringIO, :uploader=>Shrine}
911
914
  Upload (1523ms) – {:storage=>:store, :location=>"ed0e30ddec8b97813f2c1f4cfd1700b4", :io=>StringIO, :upload_options=>{}, :uploader=>Shrine}
912
915
  Exists (755ms) – {:storage=>:store, :location=>"ed0e30ddec8b97813f2c1f4cfd1700b4", :uploader=>Shrine}
@@ -957,7 +960,7 @@ Shrine.logger.level = Logger::WARN
957
960
  [`Shrine::UploadedFile`]: https://shrinerb.com/rdoc/classes/Shrine/UploadedFile/InstanceMethods.html
958
961
 
959
962
  [attacher]: #attacher
960
- [attachment]: #attachment
963
+ [attachment]: #attaching
961
964
  [backgrounding]: #backgrounding
962
965
  [direct uploads]: #direct-uploads
963
966
  [io abstraction]: #io-abstraction
@@ -1001,10 +1004,12 @@ Shrine.logger.level = Logger::WARN
1001
1004
  [ImageProcessing::MiniMagick]: https://github.com/janko/image_processing/blob/master/doc/minimagick.md#readme
1002
1005
  [ImageProcessing::Vips]: https://github.com/janko/image_processing/blob/master/doc/vips.md#readme
1003
1006
  [`file`]: http://linux.die.net/man/1/file
1007
+ [Down]: https://github.com/janko/down
1004
1008
 
1005
1009
  [activerecord plugin]: https://shrinerb.com/docs/plugins/activerecord
1006
1010
  [add_metadata plugin]: https://shrinerb.com/docs/plugins/add_metadata
1007
1011
  [backgrounding plugin]: https://shrinerb.com/docs/plugins/backgrounding
1012
+ [data_uri plugin]: https://shrinerb.com/docs/plugins/data_uri
1008
1013
  [derivation_endpoint plugin]: https://shrinerb.com/docs/plugins/derivation_endpoint
1009
1014
  [derivatives plugin]: https://shrinerb.com/docs/plugins/derivatives
1010
1015
  [determine_mime_type plugin]: https://shrinerb.com/docs/plugins/determine_mime_type