shrine 3.4.0 → 3.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +96 -0
  3. data/README.md +11 -11
  4. data/doc/advantages.md +1 -1
  5. data/doc/attacher.md +1 -1
  6. data/doc/carrierwave.md +2 -2
  7. data/doc/changing_derivatives.md +2 -1
  8. data/doc/changing_location.md +19 -6
  9. data/doc/design.md +4 -4
  10. data/doc/external/articles.md +16 -16
  11. data/doc/external/extensions.md +1 -1
  12. data/doc/getting_started.md +73 -30
  13. data/doc/multiple_files.md +57 -22
  14. data/doc/plugins/activerecord.md +91 -0
  15. data/doc/plugins/backgrounding.md +30 -4
  16. data/doc/plugins/data_uri.md +15 -0
  17. data/doc/plugins/derivation_endpoint.md +39 -1
  18. data/doc/plugins/derivatives.md +13 -2
  19. data/doc/plugins/download_endpoint.md +16 -4
  20. data/doc/plugins/dynamic_storage.md +15 -0
  21. data/doc/plugins/fallback_storage.md +90 -0
  22. data/doc/plugins/keep_files.md +6 -4
  23. data/doc/plugins/rack_response.md +9 -0
  24. data/doc/plugins/refresh_metadata.md +20 -0
  25. data/doc/plugins/sequel.md +57 -0
  26. data/doc/plugins/signature.md +8 -6
  27. data/doc/plugins/tempfile.md +14 -6
  28. data/doc/plugins/upload_options.md +12 -0
  29. data/doc/plugins/url_options.md +12 -0
  30. data/doc/plugins/validation_helpers.md +1 -1
  31. data/doc/processing.md +5 -3
  32. data/doc/refile.md +3 -3
  33. data/doc/release_notes/2.1.0.md +1 -1
  34. data/doc/release_notes/3.10.0.md +30 -0
  35. data/doc/release_notes/3.5.0.md +63 -0
  36. data/doc/release_notes/3.6.0.md +23 -0
  37. data/doc/release_notes/3.7.0.md +75 -0
  38. data/doc/release_notes/3.7.1.md +31 -0
  39. data/doc/release_notes/3.8.0.md +37 -0
  40. data/doc/release_notes/3.9.0.md +42 -0
  41. data/doc/retrieving_uploads.md +1 -1
  42. data/doc/storage/s3.md +10 -0
  43. data/doc/testing.md +45 -17
  44. data/doc/upgrading_to_3.md +3 -5
  45. data/lib/shrine/attacher.rb +41 -29
  46. data/lib/shrine/attachment.rb +2 -2
  47. data/lib/shrine/plugins/_persistence.rb +1 -1
  48. data/lib/shrine/plugins/_urlsafe_serialization.rb +4 -4
  49. data/lib/shrine/plugins/activerecord.rb +25 -4
  50. data/lib/shrine/plugins/add_metadata.rb +2 -4
  51. data/lib/shrine/plugins/atomic_helpers.rb +7 -7
  52. data/lib/shrine/plugins/backgrounding.rb +10 -10
  53. data/lib/shrine/plugins/column.rb +7 -5
  54. data/lib/shrine/plugins/data_uri.rb +28 -3
  55. data/lib/shrine/plugins/default_url.rb +4 -4
  56. data/lib/shrine/plugins/delete_raw.rb +2 -2
  57. data/lib/shrine/plugins/derivation_endpoint.rb +65 -59
  58. data/lib/shrine/plugins/derivatives.rb +35 -21
  59. data/lib/shrine/plugins/download_endpoint.rb +72 -11
  60. data/lib/shrine/plugins/entity.rb +15 -9
  61. data/lib/shrine/plugins/fallback_storage.rb +51 -0
  62. data/lib/shrine/plugins/infer_extension.rb +5 -1
  63. data/lib/shrine/plugins/instrumentation.rb +13 -9
  64. data/lib/shrine/plugins/metadata_attributes.rb +1 -1
  65. data/lib/shrine/plugins/mirroring.rb +10 -10
  66. data/lib/shrine/plugins/model.rb +12 -10
  67. data/lib/shrine/plugins/presign_endpoint.rb +13 -10
  68. data/lib/shrine/plugins/pretty_location.rb +2 -2
  69. data/lib/shrine/plugins/processing.rb +3 -3
  70. data/lib/shrine/plugins/rack_file.rb +2 -2
  71. data/lib/shrine/plugins/rack_response.rb +12 -6
  72. data/lib/shrine/plugins/refresh_metadata.rb +6 -6
  73. data/lib/shrine/plugins/remote_url.rb +4 -4
  74. data/lib/shrine/plugins/remove_attachment.rb +2 -0
  75. data/lib/shrine/plugins/remove_invalid.rb +4 -0
  76. data/lib/shrine/plugins/restore_cached_data.rb +3 -3
  77. data/lib/shrine/plugins/sequel.rb +15 -1
  78. data/lib/shrine/plugins/signature.rb +2 -2
  79. data/lib/shrine/plugins/store_dimensions.rb +2 -2
  80. data/lib/shrine/plugins/tempfile.rb +0 -2
  81. data/lib/shrine/plugins/upload_endpoint.rb +7 -5
  82. data/lib/shrine/plugins/upload_options.rb +18 -4
  83. data/lib/shrine/plugins/url_options.rb +17 -3
  84. data/lib/shrine/plugins/validation.rb +8 -8
  85. data/lib/shrine/plugins/validation_helpers.rb +2 -2
  86. data/lib/shrine/plugins/versions.rb +10 -10
  87. data/lib/shrine/plugins.rb +6 -14
  88. data/lib/shrine/storage/file_system.rb +15 -19
  89. data/lib/shrine/storage/linter.rb +8 -8
  90. data/lib/shrine/storage/memory.rb +1 -3
  91. data/lib/shrine/storage/s3.rb +60 -40
  92. data/lib/shrine/uploaded_file.rb +23 -19
  93. data/lib/shrine/version.rb +1 -1
  94. data/lib/shrine.rb +24 -20
  95. data/shrine.gemspec +10 -8
  96. metadata +52 -26
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9c012576836f3a56efa91be436999395123342c4650f76f152ef64808ce82ddb
4
- data.tar.gz: 5be0e63b923ba28f838b4f692758af3eb975c937c4b63453acc629aab0240eac
3
+ metadata.gz: 5601661d53737bf3290ec5897dc9d33cfe5edac60a7468e67de7191649671a14
4
+ data.tar.gz: bf2a26e2162a0c1805f2e8d174128e8ee5008060fdbbb9b8e358d41bfdf680a2
5
5
  SHA512:
6
- metadata.gz: da5eb6be96c3cacb0575e124b4238c038709d44f33085a5bfb4ae6cb1702d079ba0c7f1ca775828812c6d8cacd1b75aa5979c564dbe0e1ea52fea0036c0f577e
7
- data.tar.gz: fe12c86f5d826581e4ecb1b5e1951ca1330c8d6d288d19001badd79dab646013a2e57faf51d6cf7369669515636dda3058bf42a2128ea04934f7b611a53e97dd
6
+ metadata.gz: 7eb43ca8a78d4dedec0d24422ca4bc9f62eb6e454aa61ac7871760c4c398973a9787591295c39799f6b3250d4b3af9e80f7082c659fb6ed67435d775846ca5e2
7
+ data.tar.gz: 636a7343486f6baaa3fa841abcef8439eb0df5d7183d6ac39a756a508de544dd356bca2562a9e01ac76b871a29455d2a40601f8086e8050dcc793bd57fc568e0
data/CHANGELOG.md CHANGED
@@ -1,3 +1,99 @@
1
+ ## 3.10.0 (2026-09-20)
2
+
3
+ * Add `fallback_storage` plugin for reading files from a secondary storage when they're missing in the primary storage (@yegorov, @janko)
4
+
5
+ * `data_uri` – Add `:max_size` option for limiting the size of the data URI content, checked before the content is decoded (@jalrax, @janko)
6
+
7
+ * `data_uri` – Pass the error to the `:error_message` proc as an optional second argument (@jalrax, @janko)
8
+
9
+ ## 3.9.0 (2026-07-13)
10
+
11
+ * `Shrine.find_storage` now raises `Shrine::MissingStorage` (subclass of `Shrine::Error`) when the storage isn't registered, so it can be rescued separately (@janko)
12
+
13
+ * `url_options` – Allow regular expression storage keys for compatibility with `dynamic_storage` plugin (@janko)
14
+
15
+ * `upload_options` – Allow regular expression storage keys for compatibility with `dynamic_storage` plugin (@janko)
16
+
17
+ * `remove_invalid` – Fix model attribute not being cleared/reverted after deassigning invalid file (@janko)
18
+
19
+ * `activerecord`/`sequel` – Skip deleting the previous attachment when the record being saved was just created, to avoid deleting the original attachment of a duplicated record (@janko)
20
+
21
+ * `tempfile` – Allow `UploadedFile#tempfile` to be called without opening the uploaded file first (@janko)
22
+
23
+ * `activerecord` – Add `:attribute_types` option for skipping serialization of JSON/JSONB attributes declared via the Attributes API, not just database columns (@vojtad, @janko)
24
+
25
+ ## 3.8.0 (2026-06-24)
26
+
27
+ * `s3` – Use single-request uploads for smaller files again instead of always using multipart uploads (@janko)
28
+
29
+ * `derivatives` – Forward `Attacher#promote` options to `Attacher#upload_derivatives` (@milkcocoa)
30
+
31
+ * `file_system` – Prevent path traversal outside of the storage directory (@janko)
32
+
33
+ ## 3.7.1 (2026-06-03)
34
+
35
+ * Update method signatures of some plugins to work around a Bootsnap bug causing a `wrong number of arguments` error (@janko)
36
+
37
+ * `derivation_endpoint` – Add `:format` argument to `UploadedFile#derivation_url` for path extension (@janko)
38
+
39
+ * `rack_response` – Add `:etag` argument for setting a custom `ETag` (@camilohollanda)
40
+
41
+ ## 3.7.0 (2026-05-27)
42
+
43
+ * `rack_response` - Add `:etag` option for setting a custom `ETag` header (@janko)
44
+
45
+ * `download_endpoint` - Add support for expiring URLs (@davidwessman)
46
+
47
+ * `s3` - Use `TransferManager` where available instead of deprecated `upload_steam` (@danieldevlewis)
48
+
49
+ * `column` - Don't attempt to deserialize empty string as JSON (@adam12)
50
+
51
+ * `derivatives` - Add `:keep_derivatives` plugin option to keep existing derivatives when a new file is attached (@fnordfish)
52
+
53
+ * `refresh_metadata` - Add `replace:` keyword argument to `refresh_metadata!` for replacing instead of merging existing metadata (@JacobGalati)
54
+
55
+ * `backgrounding` - Fix options not being forwarded from `promote_cached` to `promote_block` (@4ndypanda)
56
+
57
+ * Fix URI default parser warnings in `UploadedFile` (@adam12)
58
+
59
+ * Drop support for Ruby < 3.2
60
+
61
+ ## 3.6.0 (2024-04-29)
62
+
63
+ * Add Rack 3 support (@tomasc, @janko)
64
+
65
+ * Make a copy of attacher context hash when duplicating the attacher (@reidab)
66
+
67
+ * An uploaded file can be implicitly re-opened after it has been closed (@jrochkind)
68
+
69
+ * Add new `:copy_options` for initializing the S3 storage (@hkdahal)
70
+
71
+ ## 3.5.0 (2023-07-06)
72
+
73
+ * Migrate website to Docusaurus v2 (@janko)
74
+
75
+ * `download_endpoint` – Return `400 Bad Request` response when serialized file component is invalid (@janko)
76
+
77
+ * `base` – Stop using obsolete `URI.regexp` in `UploadedFile#extension` (@y-yagi)
78
+
79
+ * `s3` – Add `:encoding` option to `S3#open` to be passed to `Down::ChunkedIO#initialize` (@pond)
80
+
81
+ * `s3` – Add `:max_multipart_parts` option for changing default limit of 10,000 parts (@jpl)
82
+
83
+ * `s3` – Don't inherit S3 object tags when copying from temporary to permanent storage (@jrochkind)
84
+
85
+ * `infer_extension` – Add `infer_extension` instance method to the uploader for convenience (@aried3r)
86
+
87
+ * `derivation_endpoint` – Add `:signer` plugin option for providing a custom URL signer (@thibaudgg)
88
+
89
+ * `derivatives` – Don't leak `versions_compatibility: true` setting into other uploaders (@janko)
90
+
91
+ * `derivatives` – Add `:mutex` plugin option for skipping mutex and making attacher marshallable (@janko)
92
+
93
+ * `remove_attachment` – Fix passing boolean values being broken in Ruby 3.2 (@janko)
94
+
95
+ * `model` – When duplicating a record, make the duplicated attacher reference the duplicated record (@janko)
96
+
1
97
  ## 3.4.0 (2021-06-14)
2
98
 
3
99
  * `base` – Fix passing options to `Shrine.Attachment` on Ruby 3.0 (@lucianghinda)
data/README.md CHANGED
@@ -20,20 +20,20 @@ guide]**.
20
20
 
21
21
  ## Links
22
22
 
23
- | Resource | URL |
24
- | :---------------- | :----------------------------------------------------------------------------- |
25
- | Website & Documentation | [shrinerb.com](https://shrinerb.com) |
26
- | Demo code | [Roda][roda demo] / [Rails][rails demo] |
27
- | Wiki | [github.com/shrinerb/shrine/wiki](https://github.com/shrinerb/shrine/wiki) |
28
- | Help & Discussion | [discourse.shrinerb.com](https://discourse.shrinerb.com) |
23
+ | Resource | URL |
24
+ | :---------------- | :----------------------------------------------------------------------------- |
25
+ | Website & Documentation | [shrinerb.com](https://shrinerb.com) |
26
+ | Demo code | [Roda][roda demo] / [Rails][rails demo] |
27
+ | Wiki | [github.com/shrinerb/shrine/wiki](https://github.com/shrinerb/shrine/wiki) |
28
+ | Discussion forum | [github.com/shrinerb/shrine/discussions](https://github.com/shrinerb/shrine/discussions) |
29
+ | Alternate Discussion forum | [discourse.shrinerb.com](https://discourse.shrinerb.com) |
29
30
 
30
31
  ## Setup
31
32
 
32
- Add the gem to your Gemfile:
33
+ Run:
33
34
 
34
- ```rb
35
- # Gemfile
36
- gem "shrine", "~> 3.0"
35
+ ```sh
36
+ bundle add shrine
37
37
  ```
38
38
 
39
39
  Then add `config/initializers/shrine.rb` which sets up the storage and loads
@@ -80,7 +80,7 @@ allow users to upload files:
80
80
 
81
81
  ```erb
82
82
  <%= form_for @photo do |f| %>
83
- <%= f.hidden_field :image, value: @photo.cached_image_data %>
83
+ <%= f.hidden_field :image, value: @photo.cached_image_data, id: nil %>
84
84
  <%= f.file_field :image %>
85
85
  <%= f.submit %>
86
86
  <% end %>
data/doc/advantages.md CHANGED
@@ -412,7 +412,7 @@ on top of Rack, so that they can be used with any Ruby web framework.
412
412
  [Sequel]: http://sequel.jeremyevans.net
413
413
  [ROM]: http://rom-rb.org
414
414
  [Hanami::Model]: https://github.com/hanami/model
415
- [plugin system]: https://twin.github.io/the-plugin-system-of-sequel-and-roda/
415
+ [plugin system]: https://janko.io/the-plugin-system-of-sequel-and-roda/
416
416
  [Down]: https://github.com/janko/down
417
417
  [ContentDisposition]: https://github.com/shrinerb/content_disposition
418
418
  [`file`]: http://linux.die.net/man/1/file
data/doc/attacher.md CHANGED
@@ -189,7 +189,7 @@ attacher.upload(file, location: "path/to/file") # setting upload locat
189
189
 
190
190
  ### Changes
191
191
 
192
- When a new file is attached, calling [`Attacher#finalize`](#finalization) will
192
+ When a new file is attached, calling [`Attacher#finalize`](#finalizing) will
193
193
  perform additional actions such as promotion and deleting any previous file.
194
194
  It will also trigger [validation].
195
195
 
data/doc/carrierwave.md CHANGED
@@ -368,7 +368,7 @@ Now you should be able to rewrite your application so that it uses Shrine
368
368
  instead of CarrierWave (you can consult the reference in the next section). You
369
369
  can remove the `CarrierwaveShrineSynchronization` module as well.
370
370
 
371
- ### 5. Backill metadata
371
+ ### 5. Backfill metadata
372
372
 
373
373
  You'll notice that Shrine metadata will be absent from the migrated files'
374
374
  data. You can run a script that will fill in any missing metadata defined in
@@ -646,7 +646,7 @@ Shrine.plugin :cached_attachment_data
646
646
  ```
647
647
  ```rb
648
648
  form_for @photo do |f|
649
- f.hidden_field :image, value: @photo.cached_image_data
649
+ f.hidden_field :image, value: @photo.cached_image_data, id: nil
650
650
  f.file_field :image
651
651
  end
652
652
  ```
@@ -36,7 +36,8 @@ derivatives generated). Let's assume you're generating image thumbnails:
36
36
 
37
37
  ```rb
38
38
  # Gemfile
39
- gem "image_processing", "~> 1.8"
39
+ gem "image_processing", "~> 2.0"
40
+ gem "mini_magick", "~> 5.0"
40
41
  ```
41
42
  ```rb
42
43
  require "image_processing/mini_magick"
@@ -3,7 +3,7 @@ id: changing-location
3
3
  title: Migrating File Locations
4
4
  ---
5
5
 
6
- This guide shows how to migrate the location of uploaded files on the same
6
+ This guide shows how to migrate the location of uploaded files on the same
7
7
  storage in production, with zero downtime.
8
8
 
9
9
  Let's assume we have a `Photo` model with an `image` file attachment:
@@ -31,20 +31,32 @@ to work with the previously stored urls because the files have not been migrated
31
31
  ```rb
32
32
  class ImageUploader < Shrine
33
33
  def generate_location(io, **options)
34
- # change location generation
34
+ # change location generation, eg....
35
+ [
36
+ options[:record] && options[:record].class.name.underscore,
37
+ option[:record] && options[:record].id,
38
+ super
39
+ ].compact.join("/")
35
40
  end
36
41
  end
37
42
  ```
38
43
 
39
- We can now deploy this change to production so new file uploads will be stored in
44
+ We can now deploy this change to production so new file uploads will be stored in
40
45
  the new location.
41
46
 
47
+ As seen above, we can call `super` to get the include the default location, which uses ruby
48
+ `SecureRandom.hex` to have a unique immutable storage location. While it isn't
49
+ strictly required to have a unique immutable storage location, it makes many
50
+ things work smoother when different content will get a different storage location,
51
+ and is recommended. One approach is using fixed directory/prefix as above.
52
+
53
+
42
54
  ## 2. Move existing files
43
55
 
44
56
  To move existing files to new location, run the following script. It fetches
45
57
  the photos in batches, downloads the image, and re-uploads it to the new location.
46
- We only need to migrate the files in `:store` storage need to be migrated as the files
47
- in `:cache` storage will be uploaded to the new location on promotion.
58
+ Only the files in `:store` storage need to be migrated as the files in `:cache`
59
+ storage will be uploaded to the new location on promotion.
48
60
 
49
61
  ```rb
50
62
  Photo.find_each do |photo|
@@ -99,11 +111,12 @@ class MoveFilesJob
99
111
 
100
112
  attacher = attacher_class.retrieve(model: record, name: name, file: file_data)
101
113
  old_attacher = attacher.dup
114
+ current_file = old_attacher.file
102
115
 
103
116
  attacher.set attacher.upload(attacher.file)
104
117
  attacher.set_derivatives attacher.upload_derivatives(attacher.derivatives)
105
118
 
106
- attacher.atomic_persist
119
+ attacher.atomic_persist(current_file)
107
120
  old_attacher.destroy_attached
108
121
  rescue Shrine::AttachmentChanged, ActiveRecord::RecordNotFound
109
122
  attacher&.destroy_attached
data/doc/design.md CHANGED
@@ -9,8 +9,8 @@ There are five main types of classes that you deal with in Shrine:
9
9
 
10
10
  | Class | Description |
11
11
  | :---- | :---------- |
12
- | [`Shrine::Storage::*`](#Storage) | Manages files on a particular storage service |
13
- | [`Shrine`](#Shrine) | Wraps uploads and handles loading plugins |
12
+ | [`Shrine::Storage::*`](#storage) | Manages files on a particular storage service |
13
+ | [`Shrine`](#shrine) | Wraps uploads and handles loading plugins |
14
14
  | [`Shrine::UploadedFile`](#shrineuploadedfile) | Represents a file uploaded to a storage |
15
15
  | [`Shrine::Attacher`](#shrineattacher) | Handles file attachment logic |
16
16
  | [`Shrine::Attachment`](#shrineattachment) | Provides convenience model attachment interface |
@@ -60,7 +60,7 @@ end
60
60
  ```
61
61
 
62
62
  Storages are typically not used directly, but through [`Shrine`](#shrine) and
63
- [`Shrine::UploadedFile`](#shrine-uploadedfile) classes.
63
+ [`Shrine::UploadedFile`](#shrineuploadedfile) classes.
64
64
 
65
65
  ## `Shrine`
66
66
 
@@ -264,7 +264,7 @@ When a persistence plugin is loaded ([`activerecord`][activerecord],
264
264
  [Using Attacher]: https://shrinerb.com/docs/attacher
265
265
  [Notes on study of shrine implementation]: https://bibwild.wordpress.com/2018/09/12/notes-on-study-of-shrine-implementation/
266
266
  [Creating a New Plugin]: https://shrinerb.com/docs/creating-plugins
267
- [Plugin system of Sequel and Roda]: https://twin.github.io/the-plugin-system-of-sequel-and-roda/
267
+ [Plugin system of Sequel and Roda]: https://janko.io/the-plugin-system-of-sequel-and-roda/
268
268
  [entity]: https://shrinerb.com/docs/plugins/entity
269
269
  [model]: https://shrinerb.com/docs/plugins/model
270
270
  [activerecord]: https://shrinerb.com/docs/plugins/activerecord
@@ -4,22 +4,22 @@ title: Articles
4
4
 
5
5
  ## Official articles
6
6
 
7
- | Article | Published |
8
- | :------- | --------: |
9
- | [Better File Uploads with Shrine: Eager Processing](https://twin.github.io/better-file-uploads-with-shrine-eager-processing) | 12&nbsp;Dec&nbsp;2019 |
10
- | [Shrine 3.0 Released](https://twin.github.io/shrine-3-0-released/) | 14&nbsp;Oct&nbsp;2019 |
11
- | [Upcoming Features in Shrine 3.0](https://twin.github.io/upcoming-features-in-shrine-3-0/) | 29&nbsp;Aug&nbsp;2019 |
12
- | [Better File Uploads with Shrine: Direct Uploads](https://twin.github.io/better-file-uploads-with-shrine-direct-uploads/) | 08&nbsp;Jan&nbsp;2018 |
13
- | [Better File Uploads with Shrine: Metadata](https://twin.github.io/better-file-uploads-with-shrine-metadata/) | 07&nbsp;Nov&nbsp;2016 |
14
- | [Better File Uploads with Shrine: Processing](https://twin.github.io/better-file-uploads-with-shrine-processing/) | 31&nbsp;Oct&nbsp;2016 |
15
- | [Better File Uploads with Shrine: Attachment](https://twin.github.io/better-file-uploads-with-shrine-attachment/) | 17&nbsp;Sep&nbsp;2016 |
16
- | [Better File Uploads with Shrine: Uploader](https://twin.github.io/better-file-uploads-with-shrine-uploader/) | 16&nbsp;Sep&nbsp;2016 |
17
- | [Better File Uploads with Shrine: Motivation](https://twin.github.io/better-file-uploads-with-shrine-motivation/) | 11&nbsp;Sep&nbsp;2016 |
18
- | [Resumable File Uploads in Ruby](https://twin.github.io/resumable-file-uploads-in-ruby/) | 04&nbsp;Sep&nbsp;2016 |
19
- | [Shrine meets Transloadit](https://twin.github.io/shrine-meets-transloadit/) | 11&nbsp;Jul&nbsp;2016 |
20
- | [Shrine 2.0 Released](https://twin.github.io/shrine-2-0-released/) | 20&nbsp;May&nbsp;2016 |
21
- | [Asynchronous File Uploads](http://twin.github.io/file-uploads-asynchronous-world) | 18&nbsp;Jan&nbsp;2016 |
22
- | [Introducing Shrine](http://twin.github.io/introducing-shrine) | 04&nbsp;Oct&nbsp;2015 |
7
+ | Article | Published |
8
+ | :------- | --------: |
9
+ | [Better File Uploads with Shrine: Eager Processing](https://janko.io/better-file-uploads-with-shrine-eager-processing/) | 12&nbsp;Dec&nbsp;2019 |
10
+ | [Shrine 3.0 Released](https://janko.io/shrine-3-0-released/) | 14&nbsp;Oct&nbsp;2019 |
11
+ | [Upcoming Features in Shrine 3.0](https://janko.io/upcoming-features-in-shrine-3-0/) | 29&nbsp;Aug&nbsp;2019 |
12
+ | [Better File Uploads with Shrine: Direct Uploads](https://janko.io/better-file-uploads-with-shrine-direct-uploads/) | 08&nbsp;Jan&nbsp;2018 |
13
+ | [Better File Uploads with Shrine: Metadata](https://janko.io/better-file-uploads-with-shrine-metadata/) | 07&nbsp;Nov&nbsp;2016 |
14
+ | [Better File Uploads with Shrine: Processing](https://janko.io/better-file-uploads-with-shrine-processing/) | 31&nbsp;Oct&nbsp;2016 |
15
+ | [Better File Uploads with Shrine: Attachment](https://janko.io/better-file-uploads-with-shrine-attachment/) | 17&nbsp;Sep&nbsp;2016 |
16
+ | [Better File Uploads with Shrine: Uploader](https://janko.io/better-file-uploads-with-shrine-uploader/) | 16&nbsp;Sep&nbsp;2016 |
17
+ | [Better File Uploads with Shrine: Motivation](https://janko.io/better-file-uploads-with-shrine-motivation/) | 11&nbsp;Sep&nbsp;2016 |
18
+ | [Resumable File Uploads in Ruby](https://janko.io/resumable-file-uploads-in-ruby/) | 04&nbsp;Sep&nbsp;2016 |
19
+ | [Shrine meets Transloadit](https://janko.io/shrine-meets-transloadit/) | 11&nbsp;Jul&nbsp;2016 |
20
+ | [Shrine 2.0 Released](https://janko.io/shrine-2-0-released/) | 20&nbsp;May&nbsp;2016 |
21
+ | [Asynchronous File Uploads](http://janko.io/file-uploads-asynchronous-world) | 18&nbsp;Jan&nbsp;2016 |
22
+ | [Introducing Shrine](http://janko.io/introducing-shrine) | 04&nbsp;Oct&nbsp;2015 |
23
23
 
24
24
  ## Community articles
25
25
 
@@ -35,7 +35,7 @@ title: Extensions
35
35
  | [shrine-content_addressable](https://github.com/SleeplessByte/shrine-content_addressable) | Plugin for generating content addressable locations |
36
36
  | [shrine-imgix](https://github.com/shrinerb/shrine-imgix) | Plugin for [Imgix](https://www.imgix.com/) |
37
37
  | [shrine-transloadit](https://github.com/shrinerb/shrine-transloadit) | Plugin for [Transloadit](https://transloadit.com/) |
38
- | [shrine-lambda](https://github.com/texpert/shrine-lambda) | Plugin for [AWS Lambda](https://aws.amazon.com/lambda/) |
38
+ | [shrine-aws-lambda](https://github.com/texpert/shrine-aws-lambda) | Plugin for [AWS Lambda](https://aws.amazon.com/lambda/) |
39
39
  | [hanami-shrine](https://github.com/katafrakt/hanami-shrine) | Plugin for [Hanami](https://hanamirb.org/) |
40
40
  | [shrine-mongoid](https://github.com/shrinerb/shrine-mongoid) | Plugin for [Mongoid](https://mongoid.org) |
41
41
  | [shrine-rails](https://github.com/abepetrillo/shrine-rails) | Plugin for [Rails](https://rubyonrails.org/) |
@@ -3,6 +3,9 @@ id: getting-started
3
3
  title: Getting Started
4
4
  ---
5
5
 
6
+ import Tabs from '@theme/Tabs';
7
+ import TabItem from '@theme/TabItem';
8
+
6
9
  ## Quick start
7
10
 
8
11
  Add Shrine to the Gemfile and write an initializer which sets up the storage
@@ -32,32 +35,39 @@ Next decide how you will name the attachment attribute on your model, and run a
32
35
  migration that adds an `<attachment>_data` text or JSON column, which Shrine
33
36
  will use to store all information about the attachment:
34
37
 
35
- <!--DOCUSAURUS_CODE_TABS-->
36
- <!--Sequel-->
38
+ <Tabs>
39
+ <TabItem value="sequel" label="Sequel">
40
+
37
41
  ```rb
38
42
  Sequel.migration do
39
43
  change do
40
- add_column :photos, :image_data, :text # or :jsonb
44
+ add_column :photos, :image_data, :text # or :jsonb
41
45
  end
42
46
  end
43
47
  ```
44
48
 
45
- <!--ActiveRecord-->
49
+ </TabItem>
50
+ <TabItem value="activerecord" label="Active Record">
51
+
46
52
  ```rb
47
53
  class AddImageDataToPhotos < ActiveRecord::Migration
48
54
  def change
49
- add_column :photos, :image_data, :text # or :jsonb
55
+ add_column :photos, :image_data, :text # or :jsonb
50
56
  end
51
57
  end
52
58
  ```
53
59
 
54
- <!--Rails-->
60
+ </TabItem>
61
+ <TabItem value="rails" label="Rails">
62
+
55
63
  ```rb
56
- $ rails generate migration add_image_data_to_photos image_data:text # or image_data:jsonb
64
+ $ rails generate migration add_image_data_to_photos image_data:text # or image_data:jsonb
57
65
  ```
58
- If using `jsonb` consider adding a [gin index] for fast key-value pair searchability within `image_data`.
59
66
 
60
- <!--END_DOCUSAURUS_CODE_TABS-->
67
+ </TabItem>
68
+ </Tabs>
69
+
70
+ If using `jsonb` consider adding a [gin index] for fast key-value pair searchability within `image_data`.
61
71
 
62
72
  Now you can create an uploader class for the type of files you want to upload,
63
73
  and add a virtual attribute for handling attachments using this uploader to
@@ -69,36 +79,47 @@ class ImageUploader < Shrine
69
79
  # plugins and uploading logic
70
80
  end
71
81
  ```
72
- <!--DOCUSAURUS_CODE_TABS-->
73
- <!--Sequel-->
82
+
83
+ <Tabs>
84
+ <TabItem value="sequel" label="Sequel">
85
+
74
86
  ```rb
75
87
  class Photo < Sequel::Model
76
88
  include ImageUploader::Attachment(:image) # adds an `image` virtual attribute
77
89
  end
78
90
  ```
79
- <!--ActiveRecord-->
91
+
92
+ </TabItem>
93
+ <TabItem value="activerecord" label="Active Record">
94
+
80
95
  ```rb
81
96
  class Photo < ActiveRecord::Base
82
97
  include ImageUploader::Attachment(:image) # adds an `image` virtual attribute
83
98
  end
84
99
  ```
85
- <!--END_DOCUSAURUS_CODE_TABS-->
100
+
101
+ </TabItem>
102
+ </Tabs>
86
103
 
87
104
  Let's now add the form fields which will use this virtual attribute (NOT the
88
105
  `<attachment>_data` column attribute). We need (1) a file field for choosing
89
106
  files, and (2) a hidden field for retaining the uploaded file in case of
90
107
  validation errors and for potential [direct uploads].
91
108
 
92
- <!--DOCUSAURUS_CODE_TABS-->
93
- <!--Rails form builder-->
109
+ <Tabs>
110
+ <TabItem value="rails" label="Rails form builder">
111
+
94
112
  ```rb
95
113
  form_for @photo do |f|
96
- f.hidden_field :image, value: @photo.cached_image_data
114
+ f.hidden_field :image, value: @photo.cached_image_data, id: nil
97
115
  f.file_field :image
98
116
  f.submit
99
117
  end
100
118
  ```
101
- <!--Simple Form-->
119
+
120
+ </TabItem>
121
+ <TabItem value="simple_form" label="Simple Form">
122
+
102
123
  ```rb
103
124
  simple_form_for @photo do |f|
104
125
  f.input :image, as: :hidden, input_html: { value: @photo.cached_image_data }
@@ -106,7 +127,10 @@ simple_form_for @photo do |f|
106
127
  f.button :submit
107
128
  end
108
129
  ```
109
- <!--Forme-->
130
+
131
+ </TabItem>
132
+ <TabItem value="form" label="Forme">
133
+
110
134
  ```rb
111
135
  form @photo, action: "/photos", enctype: "multipart/form-data" do |f|
112
136
  f.input :image, type: :hidden, value: @photo.cached_image_data
@@ -114,7 +138,10 @@ form @photo, action: "/photos", enctype: "multipart/form-data" do |f|
114
138
  f.button "Create"
115
139
  end
116
140
  ```
117
- <!--HTML-->
141
+
142
+ </TabItem>
143
+ <TabItem value="html" label="HTML">
144
+
118
145
  ```erb
119
146
  <form action="/photos" method="post" enctype="multipart/form-data">
120
147
  <input name="photo[image]" type="hidden" value="<%= @photo.cached_image_data %>" />
@@ -122,7 +149,9 @@ end
122
149
  <input type="submit" value="Create" />
123
150
  </form>
124
151
  ```
125
- <!--END_DOCUSAURUS_CODE_TABS-->
152
+
153
+ </TabItem>
154
+ </Tabs>
126
155
 
127
156
  Note that the file field needs to go *after* the hidden field, so that
128
157
  selecting a new file can always override the cached file in the hidden field.
@@ -133,8 +162,9 @@ will automatically generate this for you).
133
162
  When the form is submitted, in your router/controller you can assign the file
134
163
  from request params to the attachment attribute on the model.
135
164
 
136
- <!--DOCUSAURUS_CODE_TABS-->
137
- <!--Rails-->
165
+ <Tabs>
166
+ <TabItem value="rails" label="Rails">
167
+
138
168
  ```rb
139
169
  class PhotosController < ApplicationController
140
170
  def create
@@ -149,28 +179,39 @@ class PhotosController < ApplicationController
149
179
  end
150
180
  end
151
181
  ```
152
- <!--Sinatra-->
182
+
183
+ </TabItem>
184
+ <TabItem value="sinatra" label="Sinatra">
185
+
153
186
  ```rb
154
187
  post "/photos" do
155
188
  Photo.create(params[:photo])
156
189
  # ...
157
190
  end
158
191
  ```
159
- <!--END_DOCUSAURUS_CODE_TABS-->
192
+
193
+ </TabItem>
194
+ </Tabs>
160
195
 
161
196
  Once a file is uploaded and attached to the record, you can retrieve a URL to
162
197
  the uploaded file with `#<attachment>_url` and display it on the page:
163
198
 
164
- <!--DOCUSAURUS_CODE_TABS-->
165
- <!--Rails-->
199
+ <Tabs>
200
+ <TabItem value="rails" label="Rails">
201
+
166
202
  ```erb
167
203
  <%= image_tag @photo.image_url %>
168
204
  ```
169
- <!--HTML-->
205
+
206
+ </TabItem>
207
+ <TabItem value="html" label="HTML">
208
+
170
209
  ```erb
171
210
  <img src="<%= @photo.image_url %>" />
172
211
  ```
173
- <!--END_DOCUSAURUS_CODE_TABS-->
212
+
213
+ </TabItem>
214
+ </Tabs>
174
215
 
175
216
  ## Storage
176
217
 
@@ -561,7 +602,8 @@ creation:
561
602
 
562
603
  ```rb
563
604
  # Gemfile
564
- gem "image_processing", "~> 1.8"
605
+ gem "image_processing", "~> 2.0"
606
+ gem "mini_magick", "~> 5.0"
565
607
  ```
566
608
  ```rb
567
609
  Shrine.plugin :derivatives, create_on_promote: true
@@ -615,7 +657,8 @@ processing we want to perform:
615
657
 
616
658
  ```rb
617
659
  # Gemfile
618
- gem "image_processing", "~> 1.8"
660
+ gem "image_processing", "~> 2.0"
661
+ gem "mini_magick", "~> 5.0"
619
662
  ```
620
663
  ```rb
621
664
  # config/initializers/rails.rb (Rails)