shrine 3.1.0 → 3.4.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +82 -0
- data/README.md +11 -4
- data/doc/advantages.md +4 -4
- data/doc/attacher.md +2 -2
- data/doc/carrierwave.md +24 -12
- data/doc/changing_derivatives.md +1 -1
- data/doc/changing_location.md +6 -5
- data/doc/design.md +134 -85
- data/doc/direct_s3.md +26 -0
- data/doc/external/articles.md +57 -45
- data/doc/external/extensions.md +41 -35
- data/doc/external/misc.md +23 -8
- data/doc/getting_started.md +156 -85
- data/doc/metadata.md +80 -44
- data/doc/multiple_files.md +1 -1
- data/doc/paperclip.md +28 -9
- data/doc/plugins/add_metadata.md +112 -35
- data/doc/plugins/atomic_helpers.md +41 -3
- data/doc/plugins/backgrounding.md +12 -2
- data/doc/plugins/column.md +36 -7
- data/doc/plugins/default_url.md +6 -3
- data/doc/plugins/derivatives.md +83 -44
- data/doc/plugins/download_endpoint.md +5 -5
- data/doc/plugins/dynamic_storage.md +1 -1
- data/doc/plugins/entity.md +12 -4
- data/doc/plugins/form_assign.md +5 -5
- data/doc/plugins/included.md +25 -5
- data/doc/plugins/infer_extension.md +9 -0
- data/doc/plugins/instrumentation.md +1 -1
- data/doc/plugins/metadata_attributes.md +1 -0
- data/doc/plugins/mirroring.md +1 -1
- data/doc/plugins/model.md +8 -3
- data/doc/plugins/persistence.md +10 -1
- data/doc/plugins/remote_url.md +6 -1
- data/doc/plugins/remove_invalid.md +9 -1
- data/doc/plugins/sequel.md +1 -1
- data/doc/plugins/store_dimensions.md +10 -0
- data/doc/plugins/type_predicates.md +96 -0
- data/doc/plugins/upload_endpoint.md +1 -1
- data/doc/plugins/upload_options.md +1 -1
- data/doc/plugins/url_options.md +4 -4
- data/doc/plugins/validation.md +14 -4
- data/doc/plugins/versions.md +7 -7
- data/doc/processing.md +287 -123
- data/doc/refile.md +9 -9
- data/doc/release_notes/2.8.0.md +1 -1
- data/doc/release_notes/3.0.0.md +1 -1
- data/doc/release_notes/3.2.0.md +96 -0
- data/doc/release_notes/3.2.1.md +31 -0
- data/doc/release_notes/3.2.2.md +14 -0
- data/doc/release_notes/3.3.0.md +105 -0
- data/doc/release_notes/3.4.0.md +35 -0
- data/doc/securing_uploads.md +2 -2
- data/doc/storage/memory.md +19 -0
- data/doc/storage/s3.md +104 -77
- data/doc/testing.md +12 -2
- data/doc/upgrading_to_3.md +99 -53
- data/lib/shrine.rb +9 -8
- data/lib/shrine/attacher.rb +20 -10
- data/lib/shrine/attachment.rb +2 -2
- data/lib/shrine/plugins.rb +22 -0
- data/lib/shrine/plugins/activerecord.rb +3 -3
- data/lib/shrine/plugins/add_metadata.rb +20 -5
- data/lib/shrine/plugins/backgrounding.rb +2 -2
- data/lib/shrine/plugins/default_url.rb +1 -1
- data/lib/shrine/plugins/derivation_endpoint.rb +13 -8
- data/lib/shrine/plugins/derivatives.rb +59 -30
- data/lib/shrine/plugins/determine_mime_type.rb +5 -3
- data/lib/shrine/plugins/entity.rb +12 -11
- data/lib/shrine/plugins/instrumentation.rb +12 -18
- data/lib/shrine/plugins/mirroring.rb +8 -8
- data/lib/shrine/plugins/model.rb +3 -3
- data/lib/shrine/plugins/presign_endpoint.rb +16 -4
- data/lib/shrine/plugins/pretty_location.rb +1 -1
- data/lib/shrine/plugins/processing.rb +1 -1
- data/lib/shrine/plugins/refresh_metadata.rb +2 -2
- data/lib/shrine/plugins/remote_url.rb +3 -3
- data/lib/shrine/plugins/remove_attachment.rb +5 -0
- data/lib/shrine/plugins/remove_invalid.rb +10 -5
- data/lib/shrine/plugins/sequel.rb +1 -1
- data/lib/shrine/plugins/store_dimensions.rb +4 -2
- data/lib/shrine/plugins/type_predicates.rb +113 -0
- data/lib/shrine/plugins/upload_endpoint.rb +10 -5
- data/lib/shrine/plugins/upload_options.rb +2 -2
- data/lib/shrine/plugins/url_options.rb +2 -2
- data/lib/shrine/plugins/validation.rb +9 -7
- data/lib/shrine/storage/linter.rb +4 -4
- data/lib/shrine/storage/memory.rb +5 -3
- data/lib/shrine/storage/s3.rb +117 -38
- data/lib/shrine/version.rb +1 -1
- data/shrine.gemspec +8 -8
- metadata +42 -34
data/doc/direct_s3.md
CHANGED
@@ -76,6 +76,7 @@ If you're using [Uppy], this is the recommended CORS configuration for the
|
|
76
76
|
<AllowedHeader>x-amz-content-sha256</AllowedHeader>
|
77
77
|
<AllowedHeader>content-type</AllowedHeader>
|
78
78
|
<AllowedHeader>content-disposition</AllowedHeader>
|
79
|
+
<ExposeHeader>ETag</ExposeHeader>
|
79
80
|
</CORSRule>
|
80
81
|
<CORSRule>
|
81
82
|
<AllowedOrigin>*</AllowedOrigin>
|
@@ -85,6 +86,31 @@ If you're using [Uppy], this is the recommended CORS configuration for the
|
|
85
86
|
</CORSConfiguration>
|
86
87
|
```
|
87
88
|
|
89
|
+
Or in JSON format:
|
90
|
+
|
91
|
+
```json
|
92
|
+
[
|
93
|
+
{
|
94
|
+
"AllowedOrigins": [ "https://my-app.com" ],
|
95
|
+
"AllowedMethods": [ "GET", "POST", "PUT" ],
|
96
|
+
"MaxAgeSeconds": 3000,
|
97
|
+
"AllowedHeaders": [
|
98
|
+
"Authorization",
|
99
|
+
"x-amz-date",
|
100
|
+
"x-amz-content-sha256",
|
101
|
+
"Content-Type",
|
102
|
+
"Content-Disposition"
|
103
|
+
],
|
104
|
+
"ExposeHeaders": [ "ETag" ]
|
105
|
+
},
|
106
|
+
{
|
107
|
+
"AllowedOrigins": [ "*" ],
|
108
|
+
"AllowedMethods": [ "GET" ],
|
109
|
+
"MaxAgeSeconds": 3000
|
110
|
+
}
|
111
|
+
]
|
112
|
+
```
|
113
|
+
|
88
114
|
Replace `https://my-app.com` with the URL to your app (in development you can
|
89
115
|
set this to `*`). Once you've hit "Save", it may take some time for the
|
90
116
|
new CORS settings to be applied.
|
data/doc/external/articles.md
CHANGED
@@ -4,48 +4,60 @@ title: Articles
|
|
4
4
|
|
5
5
|
## Official articles
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
7
|
+
| Article | Published |
|
8
|
+
| :------- | --------: |
|
9
|
+
| [Better File Uploads with Shrine: Eager Processing](https://twin.github.io/better-file-uploads-with-shrine-eager-processing) | 12 Dec 2019 |
|
10
|
+
| [Shrine 3.0 Released](https://twin.github.io/shrine-3-0-released/) | 14 Oct 2019 |
|
11
|
+
| [Upcoming Features in Shrine 3.0](https://twin.github.io/upcoming-features-in-shrine-3-0/) | 29 Aug 2019 |
|
12
|
+
| [Better File Uploads with Shrine: Direct Uploads](https://twin.github.io/better-file-uploads-with-shrine-direct-uploads/) | 08 Jan 2018 |
|
13
|
+
| [Better File Uploads with Shrine: Metadata](https://twin.github.io/better-file-uploads-with-shrine-metadata/) | 07 Nov 2016 |
|
14
|
+
| [Better File Uploads with Shrine: Processing](https://twin.github.io/better-file-uploads-with-shrine-processing/) | 31 Oct 2016 |
|
15
|
+
| [Better File Uploads with Shrine: Attachment](https://twin.github.io/better-file-uploads-with-shrine-attachment/) | 17 Sep 2016 |
|
16
|
+
| [Better File Uploads with Shrine: Uploader](https://twin.github.io/better-file-uploads-with-shrine-uploader/) | 16 Sep 2016 |
|
17
|
+
| [Better File Uploads with Shrine: Motivation](https://twin.github.io/better-file-uploads-with-shrine-motivation/) | 11 Sep 2016 |
|
18
|
+
| [Resumable File Uploads in Ruby](https://twin.github.io/resumable-file-uploads-in-ruby/) | 04 Sep 2016 |
|
19
|
+
| [Shrine meets Transloadit](https://twin.github.io/shrine-meets-transloadit/) | 11 Jul 2016 |
|
20
|
+
| [Shrine 2.0 Released](https://twin.github.io/shrine-2-0-released/) | 20 May 2016 |
|
21
|
+
| [Asynchronous File Uploads](http://twin.github.io/file-uploads-asynchronous-world) | 18 Jan 2016 |
|
22
|
+
| [Introducing Shrine](http://twin.github.io/introducing-shrine) | 04 Oct 2015 |
|
23
|
+
|
24
|
+
## Community articles
|
25
|
+
|
26
|
+
| Article | Published |
|
27
|
+
| :------ | --------: |
|
28
|
+
| [Microsoft Azure data storage library](https://syndicode.com/2019/12/17/microsoft-azure-data-storage-library-rewrite-the-existing-library-to-get-things-done/) | 17 Dec 2019 |
|
29
|
+
| [How to use REST clients / native apps to make Shrine client uploads and S3 work for you (no Javascript, just backend)](https://dev.to/rob117/how-to-use-rest-clients--native-apps-to-make-shrine-client-uploads-and-s3-work-for-you-no-javascript-just-backend-322h) | 16 Feb 2019 |
|
30
|
+
| [GraphQL file upload with Shrine](https://blog.stanko.io/graphql-file-upload-with-shrine-45fa26463c68) | 02 Jan 2019 |
|
31
|
+
| [Notes on study of shrine implementation](https://bibwild.wordpress.com/2018/09/12/notes-on-study-of-shrine-implementation/) | 12 Sep 2018 |
|
32
|
+
| [Happy users uploading files with Rails 5, Shrine, and Vue.js](https://itnext.io/happy-users-uploading-files-with-rails-5-shrine-and-vue-js-bbcc470a327f) | 04 Sep 2018 |
|
33
|
+
| [Rails 5 + Shrine + DropzoneJS](https://stephencodes.com/rails-5-shrine-dropzonejs/) | 20 Oct 2018 |
|
34
|
+
| [How to use Trix and Shrine for WYSIWYG Editing with Drag-and-Drop Image Uploading](http://headway.io/blog/how-to-use-trix-and-shrine-for-wysiwyg-editing-with-drag-and-drop-image-uploading/) | 26 Jan 2018 |
|
35
|
+
| [Store Your Files on S3: Part 3 – Uploading from a URL](https://www.ironin.it/blog/store-your-files-on-s3-using-the-ruby-shrine-gem-part-3.html) | 28 Dec 2017 |
|
36
|
+
| [Store Your Files on S3: Part 2 – Direct Uploads](https://www.ironin.it/blog/store-your-files-on-s3-using-the-ruby-shrine-gem-part-2.html) | 15 Dec 2017 |
|
37
|
+
| [Store Your Files on S3: Part 1 – Setup & Configuration](https://www.ironin.it/blog/store-your-files-on-s3-using-the-ruby-shrine-gem-part-1.html) | 27 Nov 2017 |
|
38
|
+
| [Creating Streaming Radio With Rails and Icecast](https://scotch.io/tutorials/creating-online-streaming-radio-with-rails-and-icecast) | 06 Nov 2017 |
|
39
|
+
| [Multiple Photo Upload using Shrine](https://github.com/pyksoft/multi-photo-upload#multiple-photo-upload-using-shrine) | 02 Nov 2017 |
|
40
|
+
| [Uploading Files with Rails and ActionCable](https://scotch.io/tutorials/uploading-files-with-rails-and-actioncable) | 19 Oct 2017 |
|
41
|
+
| [Background file uploads to S3 using Shrine](https://elixirator.com/blog/background-file-uploads-to-s3-using-shrine/) | 21 Jul 2017 |
|
42
|
+
| [Upload images using Shrine.rb and Dropzone.js](https://codyeatworld.com/2017/04/18/rails-uploading-images-confidently-with-shrine-rb/) | 18 Apr 2017 |
|
43
|
+
| [Uploading Files With Rails and Shrine](https://code.tutsplus.com/tutorials/uploading-files-with-rails-and-shrine--cms-27596) | 26 Dec 2016 |
|
44
|
+
| [Rails File Uploading You Can Believe in with Shrine](http://www.sitepoint.com/rails-file-uploading-you-can-believe-in-with-shrine/) | 11 Apr 2016 |
|
45
|
+
| [Uploading files with Shrine in Hanami](http://katafrakt.me/2016/02/04/shrine-hanami-uploads/) | 04 Feb 2016 |
|
46
|
+
|
47
|
+
## Screencasts
|
48
|
+
|
49
|
+
| Screencast | Source | Published |
|
50
|
+
| :---- | :------ | --------: |
|
51
|
+
| [Testing File Uploads in Rails with Shrine](https://gorails.com/episodes/testing-file-uploads-with-shrine?autoplay=1) | GoRails | 23 Mar 2020 |
|
52
|
+
| [File Uploads in Rails with Shrine](https://gorails.com/episodes/rails-file-uploads-with-shrine?autoplay=1) | GoRails | 16 Mar 2020 |
|
53
|
+
| [Uploading Files to DigitalOcean Spaces](https://gorails.com/episodes/digital-ocean-spaces-with-rails?autoplay=1) | GoRails | 31 Oct 2017 |
|
54
|
+
| [Trix WYSIWYG Editor And File Uploads](https://gorails.com/episodes/trix-editor?autoplay=1) | GoRails | 03 Oct 2017 |
|
55
|
+
| [Multiple File Uploads with Shrine](https://gorails.com/episodes/multiple-file-uploads-with-shrine?autoplay=1) | GoRails | 14 Dec 2016 |
|
56
|
+
| [Backgrounding and Video Transcoding](https://gorails.com/episodes/shrine-background-and-video-transcoding?autoplay=1) | GoRails | 03 Nov 2016 |
|
57
|
+
|
58
|
+
## Talks
|
59
|
+
|
60
|
+
| Talk | Source | Date |
|
61
|
+
| :---- | :------ | --------: |
|
62
|
+
| [Handling file uploads for a modern developer](https://www.youtube.com/watch?v=fP2JGjTZU2s) | wroc_love.rb | 24 Mar 2019 |
|
63
|
+
| [Shrine – Handle File Uploads like it's 2017](https://www.youtube.com/watch?v=plD-RkKEay0) | Melbourne Ruby | 27 Feb 2017 |
|
data/doc/external/extensions.md
CHANGED
@@ -4,44 +4,50 @@ title: Extensions
|
|
4
4
|
|
5
5
|
## Storages
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
* [shrine-storage-you_tube](https://github.com/thedyrt/shrine-storage-you_tube)
|
25
|
-
* [shrine-webdav](https://github.com/funbox/shrine-webdav)
|
7
|
+
| Gem | Description |
|
8
|
+
| :---- | :---------- |
|
9
|
+
| [shrine-aliyun-oss](https://github.com/zillou/shrine-aliyun-oss) | Storage using [Alibaba Cloud OSS](https://www.alibabacloud.com/product/oss) |
|
10
|
+
| [shrine-cloudinary](https://github.com/shrinerb/shrine-cloudinary) | Storage using [Cloudinary](https://cloudinary.com/) |
|
11
|
+
| [shrine-flickr](https://github.com/shrinerb/shrine-flickr) | Storage using [Flickr](https://flickr.com/) |
|
12
|
+
| [shrine-fog](https://github.com/shrinerb/shrine-fog) | Storage using [Fog](http://fog.io/) |
|
13
|
+
| [shrine-ftp](https://github.com/ProjectResound/shrine-ftp) | Storage using an FTP server |
|
14
|
+
| [shrine-google_cloud_storage](https://github.com/renchap/shrine-google_cloud_storage) | Storage using [Google Cloud Storage](https://cloud.google.com/storage/) |
|
15
|
+
| [shrine-gdrive_storage](https://github.com/edwardsharp/shrine-gdrive_storage) | Storage using [Google Drive](https://www.google.com/drive/) |
|
16
|
+
| [shrine-gridfs](https://github.com/shrinerb/shrine-gridfs) | Storage using [Mongo GridFS](https://docs.mongodb.com/manual/core/gridfs/) |
|
17
|
+
| [shrine-redis](https://github.com/dbongo/shrine-redis) | Storage using [Redis](https://redis.io/) |
|
18
|
+
| [shrine-scp](https://github.com/jordanandree/shrine-scp) | Storage using `scp` |
|
19
|
+
| [shrine-sql](https://github.com/shrinerb/shrine-sql) | Storage using an SQL database |
|
20
|
+
| [shrine-uploadcare](https://github.com/shrinerb/shrine-uploadcare) | Storage using [Uploadcare](https://uploadcare.com) |
|
21
|
+
| [shrine-url](https://github.com/shrinerb/shrine-url) | Storage for handling remote URLs |
|
22
|
+
| [shrine-storage-you_tube](https://github.com/thedyrt/shrine-storage-you_tube) | Storage using [YouTube](https://www.youtube.com/) |
|
23
|
+
| [shrine-webdav](https://github.com/funbox/shrine-webdav) | Storage using a [WebDAV](https://en.wikipedia.org/wiki/WebDAV) server |
|
26
24
|
|
27
25
|
## Plugins
|
28
26
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
27
|
+
| Gem | Description |
|
28
|
+
| :---- | :-------- |
|
29
|
+
| [administrate-field-shrine](https://github.com/catsky/administrate-field-shrine) | Plugin for [Administrate](https://github.com/thoughtbot/administrate) |
|
30
|
+
| [rails_admin_shrine](https://github.com/iquest/rails_admin_shrine) | Plugin for [RailsAdmin](https://github.com/sferik/rails_admin) |
|
31
|
+
| [shrine-blurhash](https://github.com/renchap/shrine-blurhash) | Plugin for computing [Blurhash](https://blurha.sh/) on images |
|
32
|
+
| [shrine-cloudimage](https://github.com/janklimo/shrine-cloudimage) | Plugin for [Cloudimage](https://www.cloudimage.io/) |
|
33
|
+
| [shrine-color](https://github.com/jnylen/shrine-color) | Plugin for finding dominant color in an image |
|
34
|
+
| [shrine-configurable_storage](https://github.com/SleeplessByte/shrine-configurable_storage) | Plugin for lazy storage registration |
|
35
|
+
| [shrine-content_addressable](https://github.com/SleeplessByte/shrine-content_addressable) | Plugin for generating content addressable locations |
|
36
|
+
| [shrine-imgix](https://github.com/shrinerb/shrine-imgix) | Plugin for [Imgix](https://www.imgix.com/) |
|
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/) |
|
39
|
+
| [hanami-shrine](https://github.com/katafrakt/hanami-shrine) | Plugin for [Hanami](https://hanamirb.org/) |
|
40
|
+
| [shrine-mongoid](https://github.com/shrinerb/shrine-mongoid) | Plugin for [Mongoid](https://mongoid.org) |
|
41
|
+
| [shrine-rails](https://github.com/abepetrillo/shrine-rails) | Plugin for [Rails](https://rubyonrails.org/) |
|
42
|
+
| [shrine-rom](https://github.com/shrinerb/shrine-rom) | Plugin for [ROM](https://rom-rb.org/) |
|
43
|
+
| [shrine-tus](https://github.com/shrinerb/shrine-tus) | Plugin for [tus](https://tus.io) server integration |
|
41
44
|
|
42
45
|
## Libraries
|
43
46
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
47
|
+
| Gem | Description |
|
48
|
+
| :----- | :------- |
|
49
|
+
| [ckeditor](https://github.com/galetahub/ckeditor) | Integration for [CKEditor](https://ckeditor.com/ckeditor-4/) |
|
50
|
+
| [faster_s3_url](https://github.com/jrochkind/faster_s3_url) | Optimized generation of public and presigned AWS S3 GET URLs |
|
51
|
+
| [imgproxy](https://github.com/imgproxy/imgproxy.rb) | Integration for [imgproxy](https://github.com/imgproxy/imgproxy) |
|
52
|
+
| [rails_admin](https://github.com/sferik/rails_admin) | Integration for [RailsAdmin](https://github.com/sferik/rails_admin) |
|
53
|
+
| [uppy-s3_multipart](https://github.com/janko/uppy-s3_multipart) | Integration for [Uppy AWS S3 Multipart](https://uppy.io/docs/aws-s3-multipart/) |
|
data/doc/external/misc.md
CHANGED
@@ -4,14 +4,29 @@ title: Miscellaneous
|
|
4
4
|
|
5
5
|
## Demos
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
7
|
+
| Demo | Description |
|
8
|
+
| :--- | :---------- |
|
9
|
+
| [Dropzone demo](https://github.com/codyeatworld/example-shrine-dropzone) | Shows direct upload using [Dropzone.js] |
|
10
|
+
| [Hanami demo](https://github.com/katafrakt/hanami-shrine-example) | Shows file attachment in [Hanami] |
|
11
|
+
| [Crop demo](https://github.com/shrinerb/shrine-crop-example) | Shows image cropping using [Cropper.js] |
|
12
|
+
| [Rails demo](https://github.com/erikdahlstrand/shrine-rails-example) | Shows direct upload in [Rails] |
|
13
|
+
| [Resumable uploads demo](https://github.com/shrinerb/shrine-tus-demo) | Shows resumable direct upload on [tus] |
|
14
|
+
| [Roda demo (official)](https://github.com/shrinerb/shrine/tree/master/demo) | Shows direct upload in [Roda] |
|
15
|
+
| [rom-rb & dry-rb demo](https://github.com/shrinerb/shrine-rom/tree/master/demo) | Shows file attachment with [rom-rb] and [dry-rb] |
|
16
|
+
| [Transloadit demo](https://github.com/shrinerb/shrine-transloadit/tree/master/demo) | Shows file processing using [Transloadit] |
|
14
17
|
|
15
18
|
## Projects
|
16
19
|
|
17
|
-
|
20
|
+
| Project | Description |
|
21
|
+
| :------ | :---------- |
|
22
|
+
| [CortexCMS](https://docs.cortexcms.org) | An open source, enterprise content management and distribution platform |
|
23
|
+
|
24
|
+
[Dropzone.js]: https://www.dropzonejs.com/
|
25
|
+
[Hanami]: https://hanamirb.org/
|
26
|
+
[Cropper.js]: https://github.com/fengyuanchen/cropperjs
|
27
|
+
[Rails]: https://rubyonrails.org/
|
28
|
+
[tus]: https://tus.io/
|
29
|
+
[Roda]: https://roda.jeremyevans.net/
|
30
|
+
[rom-rb]: https://rom-rb.org/
|
31
|
+
[dry-rb]: https://dry-rb.org/
|
32
|
+
[Transloadit]: https://transloadit.com/
|
data/doc/getting_started.md
CHANGED
@@ -37,22 +37,26 @@ will use to store all information about the attachment:
|
|
37
37
|
```rb
|
38
38
|
Sequel.migration do
|
39
39
|
change do
|
40
|
-
add_column :photos, :image_data, :text # or :jsonb
|
40
|
+
add_column :photos, :image_data, :text # or :jsonb
|
41
41
|
end
|
42
42
|
end
|
43
43
|
```
|
44
|
+
|
44
45
|
<!--ActiveRecord-->
|
45
46
|
```rb
|
46
47
|
class AddImageDataToPhotos < ActiveRecord::Migration
|
47
48
|
def change
|
48
|
-
add_column :photos, :image_data, :text # or :jsonb
|
49
|
+
add_column :photos, :image_data, :text # or :jsonb
|
49
50
|
end
|
50
51
|
end
|
51
52
|
```
|
53
|
+
|
52
54
|
<!--Rails-->
|
55
|
+
```rb
|
56
|
+
$ rails generate migration add_image_data_to_photos image_data:text # or image_data:jsonb
|
53
57
|
```
|
54
|
-
|
55
|
-
|
58
|
+
If using `jsonb` consider adding a [gin index] for fast key-value pair searchability within `image_data`.
|
59
|
+
|
56
60
|
<!--END_DOCUSAURUS_CODE_TABS-->
|
57
61
|
|
58
62
|
Now you can create an uploader class for the type of files you want to upload,
|
@@ -110,6 +114,14 @@ form @photo, action: "/photos", enctype: "multipart/form-data" do |f|
|
|
110
114
|
f.button "Create"
|
111
115
|
end
|
112
116
|
```
|
117
|
+
<!--HTML-->
|
118
|
+
```erb
|
119
|
+
<form action="/photos" method="post" enctype="multipart/form-data">
|
120
|
+
<input name="photo[image]" type="hidden" value="<%= @photo.cached_image_data %>" />
|
121
|
+
<input name="photo[image] "type="file" />
|
122
|
+
<input type="submit" value="Create" />
|
123
|
+
</form>
|
124
|
+
```
|
113
125
|
<!--END_DOCUSAURUS_CODE_TABS-->
|
114
126
|
|
115
127
|
Note that the file field needs to go *after* the hidden field, so that
|
@@ -167,9 +179,13 @@ specific storage service, by implementing a common public interface. Storage
|
|
167
179
|
instances are registered under an identifier in `Shrine.storages`, so that they
|
168
180
|
can later be used by [uploaders][uploader].
|
169
181
|
|
170
|
-
|
171
|
-
|
172
|
-
|
182
|
+
Shrine ships with the following storages:
|
183
|
+
|
184
|
+
* [`Shrine::Storage::FileSystem`][FileSystem] – stores files on disk
|
185
|
+
* [`Shrine::Storage::S3`][S3] – stores files on [AWS S3] (or [DigitalOcean Spaces], [MinIO], ...)
|
186
|
+
* [`Shrine::Storage::Memory`][Memory] – stores file in memory (convenient for [testing][Testing with Shrine])
|
187
|
+
|
188
|
+
Here is how we might configure Shrine with S3 storage:
|
173
189
|
|
174
190
|
```rb
|
175
191
|
# Gemfile
|
@@ -180,9 +196,9 @@ require "shrine/storage/s3"
|
|
180
196
|
|
181
197
|
s3_options = {
|
182
198
|
bucket: "<YOUR BUCKET>", # required
|
199
|
+
region: "<YOUR REGION>", # required
|
183
200
|
access_key_id: "<YOUR ACCESS KEY ID>",
|
184
201
|
secret_access_key: "<YOUR SECRET ACCESS KEY>",
|
185
|
-
region: "<YOUR REGION>",
|
186
202
|
}
|
187
203
|
|
188
204
|
Shrine.storages = {
|
@@ -196,9 +212,9 @@ suitable for [direct uploads][presigned upload]. The `:cache` and `:store`
|
|
196
212
|
names are special only in terms that the [attacher] will automatically pick
|
197
213
|
them up, you can also register more storage objects under different names.
|
198
214
|
|
199
|
-
See the [FileSystem]
|
200
|
-
more Shrine storages][storages] provided by external gems, and you can
|
201
|
-
[create your own storage][Creating Storages].
|
215
|
+
See the [FileSystem]/[S3]/[Memory] storage docs for more details. There are
|
216
|
+
[many more Shrine storages][storages] provided by external gems, and you can
|
217
|
+
also [create your own storage][Creating Storages].
|
202
218
|
|
203
219
|
## Uploader
|
204
220
|
|
@@ -256,14 +272,14 @@ Shrine is able to upload any IO-like object that implement methods [`#read`],
|
|
256
272
|
[`#rewind`], [`#eof?`] and [`#close`] whose behaviour matches the [`IO`] class.
|
257
273
|
This includes but is not limited to the following objects:
|
258
274
|
|
259
|
-
* `File`
|
260
|
-
* `Tempfile`
|
261
|
-
* `StringIO`
|
262
|
-
* `ActionDispatch::Http::UploadedFile`
|
263
|
-
* `Shrine::RackFile`
|
264
|
-
* `Shrine::DataFile`
|
265
|
-
* `Shrine::UploadedFile`
|
266
|
-
* `Down::ChunkedIO`
|
275
|
+
* [`File`](https://ruby-doc.org/core/File.html)
|
276
|
+
* [`Tempfile`](https://ruby-doc.org/stdlib/libdoc/tempfile/rdoc/Tempfile.html)
|
277
|
+
* [`StringIO`](https://ruby-doc.org/stdlib/libdoc/stringio/rdoc/StringIO.html)
|
278
|
+
* [`ActionDispatch::Http::UploadedFile`](https://api.rubyonrails.org/classes/ActionDispatch/Http/UploadedFile.html)
|
279
|
+
* [`Shrine::RackFile`](https://shrinerb.com/docs/plugins/rack_file)
|
280
|
+
* [`Shrine::DataFile`](https://shrinerb.com/docs/plugins/data_uri)
|
281
|
+
* [`Shrine::UploadedFile`](#uploaded-file)
|
282
|
+
* [`Down::ChunkedIO`](https://github.com/janko/down#streaming)
|
267
283
|
* ...
|
268
284
|
|
269
285
|
```rb
|
@@ -424,9 +440,9 @@ See [Using Attacher] guide for more details.
|
|
424
440
|
|
425
441
|
### Temporary storage
|
426
442
|
|
427
|
-
Shrine uses temporary storage to support
|
428
|
-
|
429
|
-
files
|
443
|
+
Shrine uses temporary storage to support [file validation][validation] and
|
444
|
+
[direct uploads]. If you don't need these features, you can tell Shrine to
|
445
|
+
upload files directly to permanent storage:
|
430
446
|
|
431
447
|
```rb
|
432
448
|
Shrine.plugin :model, cache: false
|
@@ -446,7 +462,7 @@ attacher.file.storage_key #=> :store
|
|
446
462
|
|
447
463
|
## Plugin system
|
448
464
|
|
449
|
-
By default Shrine comes with a small core which provides only the essential
|
465
|
+
By default, Shrine comes with a small core which provides only the essential
|
450
466
|
functionality. All additional features are available via [plugins], which also
|
451
467
|
ship with Shrine. This way you can choose exactly what and how much Shrine does
|
452
468
|
for you, and you load the code only for features that you use.
|
@@ -469,6 +485,12 @@ If you want to extend Shrine functionality with custom behaviour, you can also
|
|
469
485
|
[create your own plugin][Creating Plugins]. There are also additional [external
|
470
486
|
plugins] created by others.
|
471
487
|
|
488
|
+
> NOTE: An uploader class will inherit a copy of current superclass' plugin
|
489
|
+
> options at the time of subclassing. This means you should *not* load
|
490
|
+
> additional plugins on a superclass after the subclass has already been
|
491
|
+
> created, because new options will not get applied to the subclass, which
|
492
|
+
> can result in errors.
|
493
|
+
|
472
494
|
## Metadata
|
473
495
|
|
474
496
|
Shrine automatically extracts some basic file metadata and saves them to the
|
@@ -504,7 +526,7 @@ gem "marcel", "~> 0.3"
|
|
504
526
|
Shrine.plugin :determine_mime_type, analyzer: :marcel
|
505
527
|
```
|
506
528
|
```rb
|
507
|
-
photo = Photo.
|
529
|
+
photo = Photo.new(image: StringIO.new("<?php ... ?>"))
|
508
530
|
photo.image.mime_type #=> "application/x-php"
|
509
531
|
```
|
510
532
|
|
@@ -517,10 +539,10 @@ the [Extracting Metadata] guide for more details.
|
|
517
539
|
|
518
540
|
## Processing
|
519
541
|
|
520
|
-
Shrine allows you to process attached files
|
521
|
-
example, if your app is accepting image uploads, you can generate a
|
522
|
-
set of
|
523
|
-
thumbnails generated dynamically as they're needed.
|
542
|
+
Shrine allows you to process attached files both "eagerly" and "on-the-fly".
|
543
|
+
For example, if your app is accepting image uploads, you can generate a
|
544
|
+
predefined set of thumbnails when the image is attached to a record, or you
|
545
|
+
can have thumbnails generated dynamically as they're needed.
|
524
546
|
|
525
547
|
For image processing, it's recommended to use the **[ImageProcessing]** gem,
|
526
548
|
which is a high-level wrapper for processing with
|
@@ -530,17 +552,19 @@ which is a high-level wrapper for processing with
|
|
530
552
|
$ brew install imagemagick vips
|
531
553
|
```
|
532
554
|
|
533
|
-
###
|
555
|
+
### Eager processing
|
534
556
|
|
535
|
-
|
536
|
-
pre-defined processed files
|
557
|
+
We can use the [`derivatives`][derivatives plugin] plugin to generate a
|
558
|
+
pre-defined set of processed files (e.g. image thumbnails). We do this by
|
559
|
+
registering a derivatives processor block and then explicitly triggering
|
560
|
+
creation:
|
537
561
|
|
538
562
|
```rb
|
539
563
|
# Gemfile
|
540
564
|
gem "image_processing", "~> 1.8"
|
541
565
|
```
|
542
566
|
```rb
|
543
|
-
Shrine.plugin :derivatives
|
567
|
+
Shrine.plugin :derivatives, create_on_promote: true
|
544
568
|
```
|
545
569
|
```rb
|
546
570
|
require "image_processing/mini_magick"
|
@@ -559,32 +583,29 @@ end
|
|
559
583
|
```
|
560
584
|
```rb
|
561
585
|
photo = Photo.new(image: file)
|
562
|
-
photo.
|
563
|
-
photo.save
|
586
|
+
photo.save # automatically creates derivatives on promotion
|
564
587
|
```
|
565
588
|
|
566
|
-
|
567
|
-
route make sure to trigger derivatives creation for new attachments:
|
589
|
+
You can then retrieve the URL of a processed derivative:
|
568
590
|
|
569
591
|
```rb
|
570
|
-
photo.
|
592
|
+
photo.image_url(:large) #=> "https://s3.amazonaws.com/path/to/large.jpg"
|
571
593
|
```
|
572
594
|
|
573
|
-
|
574
|
-
|
575
|
-
[`Shrine::UploadedFile`][uploaded file] objects:
|
595
|
+
The derivatives data is stored in the `<attachment>_data` column, and you can
|
596
|
+
retrieve them as [`Shrine::UploadedFile`][uploaded file] objects:
|
576
597
|
|
577
598
|
```rb
|
578
|
-
photo.image(:large)
|
579
|
-
photo.image(:large).url
|
580
|
-
photo.image(:large).size
|
581
|
-
photo.image(:large).mime_type
|
599
|
+
photo.image(:large) #=> #<Shrine::UploadedFile id="path/to/large.jpg" storage=:store metadata={...}>
|
600
|
+
photo.image(:large).url #=> "https://s3.amazonaws.com/path/to/large.jpg"
|
601
|
+
photo.image(:large).size #=> 5825949
|
602
|
+
photo.image(:large).mime_type #=> "image/jpeg"
|
582
603
|
```
|
583
604
|
|
584
|
-
For more details, see the [
|
585
|
-
|
605
|
+
For more details, see the [File Processing] guide and the
|
606
|
+
[`derivatives`][derivatives plugin] plugin documentation.
|
586
607
|
|
587
|
-
###
|
608
|
+
### On-the-fly processing
|
588
609
|
|
589
610
|
On-the-fly processing is provided by the
|
590
611
|
[`derivation_endpoint`][derivation_endpoint plugin] plugin. To set it up, we
|
@@ -597,24 +618,28 @@ processing we want to perform:
|
|
597
618
|
gem "image_processing", "~> 1.8"
|
598
619
|
```
|
599
620
|
```rb
|
600
|
-
# config/initializers/
|
621
|
+
# config/initializers/rails.rb (Rails)
|
622
|
+
# ...
|
623
|
+
Shrine.plugin :derivation_endpoint, secret_key: "<YOUR_SECRET_KEY>"
|
624
|
+
```
|
625
|
+
```rb
|
601
626
|
require "image_processing/mini_magick"
|
602
627
|
|
603
|
-
Shrine
|
604
|
-
|
605
|
-
prefix: "derivations" # needs to match the mount point in routes
|
628
|
+
class ImageUploader < Shrine
|
629
|
+
plugin :derivation_endpoint, prefix: "derivations/image" # matches mount point
|
606
630
|
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
631
|
+
derivation :thumbnail do |file, width, height|
|
632
|
+
ImageProcessing::MiniMagick
|
633
|
+
.source(file)
|
634
|
+
.resize_to_limit!(width.to_i, height.to_i)
|
635
|
+
end
|
611
636
|
end
|
612
637
|
```
|
613
638
|
```rb
|
614
639
|
# config/routes.rb (Rails)
|
615
640
|
Rails.application.routes.draw do
|
616
641
|
# ...
|
617
|
-
mount
|
642
|
+
mount ImageUploader.derivation_endpoint => "/derivations/image"
|
618
643
|
end
|
619
644
|
```
|
620
645
|
|
@@ -623,7 +648,7 @@ processing:
|
|
623
648
|
|
624
649
|
```rb
|
625
650
|
photo.image.derivation_url(:thumbnail, 600, 400)
|
626
|
-
#=> "/derivations/thumbnail/600/400/eyJpZCI6ImZvbyIsInN0b3JhZ2UiOiJzdG9yZSJ9?signature=..."
|
651
|
+
#=> "/derivations/image/thumbnail/600/400/eyJpZCI6ImZvbyIsInN0b3JhZ2UiOiJzdG9yZSJ9?signature=..."
|
627
652
|
```
|
628
653
|
|
629
654
|
The on-the-fly processing feature is highly customizable, see the
|
@@ -661,36 +686,85 @@ For more details, see the [File Validation] guide and
|
|
661
686
|
|
662
687
|
## Location
|
663
688
|
|
664
|
-
Shrine automatically
|
665
|
-
default the hierarchy is flat, meaning all files are stored in the root
|
666
|
-
directory of the storage.
|
667
|
-
|
668
|
-
|
689
|
+
Shrine automatically generates random locations before uploading files. By
|
690
|
+
default, the hierarchy is flat, meaning all files are stored in the root
|
691
|
+
directory of the storage.
|
692
|
+
|
693
|
+
```
|
694
|
+
024d9fe83bf4fafb.jpg
|
695
|
+
768a336bf54de219.jpg
|
696
|
+
adfaa363629f7fc5.png
|
697
|
+
...
|
698
|
+
```
|
699
|
+
|
700
|
+
The [`pretty_location`][pretty_location plugin] plugin provides a good default
|
701
|
+
hierarchy:
|
702
|
+
|
703
|
+
```rb
|
704
|
+
Shrine.plugin :pretty_location
|
705
|
+
```
|
706
|
+
```
|
707
|
+
user/
|
708
|
+
564/
|
709
|
+
avatar/
|
710
|
+
aa3e0cd715.jpg
|
711
|
+
thumb-493g82jf23.jpg
|
712
|
+
photo/
|
713
|
+
123/
|
714
|
+
image/
|
715
|
+
13f8a7bc18.png
|
716
|
+
thumb-9be62da67e.png
|
717
|
+
...
|
718
|
+
```
|
719
|
+
|
720
|
+
But you can also override `Shrine#generate_location` with a custom
|
721
|
+
implementation, for example:
|
669
722
|
|
670
723
|
```rb
|
671
724
|
class ImageUploader < Shrine
|
672
725
|
def generate_location(io, record: nil, derivative: nil, **)
|
673
|
-
|
674
|
-
style = derivative ? "thumbs" : "originals"
|
675
|
-
name = super # the default unique identifier
|
726
|
+
return super unless record
|
676
727
|
|
677
|
-
|
728
|
+
table = record.class.table_name
|
729
|
+
id = record.id
|
730
|
+
prefix = derivative || "original"
|
731
|
+
|
732
|
+
"uploads/#{table}/#{id}/#{prefix}-#{super}"
|
678
733
|
end
|
679
734
|
end
|
680
735
|
```
|
681
736
|
```
|
682
737
|
uploads/
|
683
738
|
photos/
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
739
|
+
123/
|
740
|
+
original-afe929b8b4.jpg
|
741
|
+
small-ad61f25883.jpg
|
742
|
+
medium-41b75c42bb.jpg
|
743
|
+
large-73e67abe50.jpg
|
744
|
+
...
|
689
745
|
```
|
690
746
|
|
691
|
-
|
692
|
-
|
693
|
-
|
747
|
+
> There should always be a random component in the location, so that the ORM
|
748
|
+
dirty tracking is detected properly.
|
749
|
+
|
750
|
+
The `Shrine#generate_location` method contains a lot of useful context for the
|
751
|
+
upcoming upload:
|
752
|
+
|
753
|
+
```rb
|
754
|
+
class ImageUploader < Shrine
|
755
|
+
def generate_location(io, record: nil, name: nil, derivative: nil, metadata: {}, **options)
|
756
|
+
storage_key #=> :cache, :store, ...
|
757
|
+
io #=> #<File>, #<Shrine::UploadedFile>, ...
|
758
|
+
record #=> #<Photo>, #<User>, ...
|
759
|
+
name #=> :image, :avatar, ...
|
760
|
+
derivative #=> :small, :medium, :large, ... (derivatives plugin)
|
761
|
+
metadata #=> { "filename" => "nature.jpg", "mime_type" => "image/jpeg", "size" => 18573, ... }
|
762
|
+
options #=> { ... other uploader options ... }
|
763
|
+
|
764
|
+
# ...
|
765
|
+
end
|
766
|
+
end
|
767
|
+
```
|
694
768
|
|
695
769
|
## Direct uploads
|
696
770
|
|
@@ -725,7 +799,7 @@ Shrine.plugin :upload_endpoint
|
|
725
799
|
# config/routes.rb (Rails)
|
726
800
|
Rails.application.routes.draw do
|
727
801
|
# ...
|
728
|
-
mount
|
802
|
+
mount Shrine.upload_endpoint(:cache) => "/upload" # POST /upload
|
729
803
|
end
|
730
804
|
```
|
731
805
|
|
@@ -835,7 +909,7 @@ resumable uploads from scratch, it includes a complete JavaScript example
|
|
835
909
|
|
836
910
|
## Backgrounding
|
837
911
|
|
838
|
-
The [`backgrounding`][backgrounding plugin] allows you to move file promotion
|
912
|
+
The [`backgrounding`][backgrounding plugin] plugin allows you to move file promotion
|
839
913
|
and deletion into a background job, using the backgrounding library [of your
|
840
914
|
choice][Backgrounding Libraries]:
|
841
915
|
|
@@ -852,7 +926,7 @@ end
|
|
852
926
|
class PromoteJob
|
853
927
|
include Sidekiq::Worker
|
854
928
|
|
855
|
-
def perform(attacher_class, record_class,
|
929
|
+
def perform(attacher_class, record_class, record_id, name, file_data)
|
856
930
|
attacher_class = Object.const_get(attacher_class)
|
857
931
|
record = Object.const_get(record_class).find(record_id) # if using Active Record
|
858
932
|
|
@@ -896,6 +970,8 @@ s3 = Shrine.storages[:cache]
|
|
896
970
|
s3.clear! { |object| object.last_modified < Time.now - 7*24*60*60 } # delete files older than 1 week
|
897
971
|
```
|
898
972
|
|
973
|
+
For S3, it may be easier and cheaper to use [S3 bucket lifecycle expiration rules](http://docs.aws.amazon.com/AmazonS3/latest/UG/lifecycle-configuration-bucket-no-versioning.html) instead.
|
974
|
+
|
899
975
|
## Logging
|
900
976
|
|
901
977
|
The [`instrumentation`][instrumentation plugin] plugin sends and logs events for
|
@@ -946,7 +1022,6 @@ In tests you might want to tell Shrine to log only warnings:
|
|
946
1022
|
Shrine.logger.level = Logger::WARN
|
947
1023
|
```
|
948
1024
|
|
949
|
-
[Advantages of Shrine]: https://shrinerb.com/docs/advantages
|
950
1025
|
[Creating Plugins]: https://shrinerb.com/docs/creating-plugins
|
951
1026
|
[Creating Storages]: https://shrinerb.com/docs/creating-storages
|
952
1027
|
[Direct Uploads to S3]: https://shrinerb.com/docs/direct-s3
|
@@ -957,24 +1032,19 @@ Shrine.logger.level = Logger::WARN
|
|
957
1032
|
[Using Attacher]: https://shrinerb.com/docs/attacher
|
958
1033
|
[FileSystem]: https://shrinerb.com/docs/storage/file-system
|
959
1034
|
[S3]: https://shrinerb.com/docs/storage/s3
|
1035
|
+
[Memory]: https://shrinerb.com/docs/storage/memory
|
1036
|
+
[Testing with Shrine]: https://shrinerb.com/docs/testing
|
960
1037
|
[`Shrine::UploadedFile`]: https://shrinerb.com/rdoc/classes/Shrine/UploadedFile/InstanceMethods.html
|
961
1038
|
|
962
1039
|
[attacher]: #attacher
|
963
1040
|
[attachment]: #attaching
|
964
|
-
[backgrounding]: #backgrounding
|
965
1041
|
[direct uploads]: #direct-uploads
|
966
1042
|
[io abstraction]: #io-abstraction
|
967
1043
|
[location]: #location
|
968
1044
|
[metadata]: #metadata
|
969
|
-
[up front]: #processing-up-front
|
970
|
-
[on-the-fly]: #processing-on-the-fly
|
971
|
-
[plugin system]: #plugin-system
|
972
|
-
[simple upload]: #simple-direct-upload
|
973
1045
|
[presigned upload]: #presigned-direct-upload
|
974
|
-
[resumable upload]: #resumable-direct-upload
|
975
1046
|
[storage]: #storage
|
976
1047
|
[uploaded file]: #uploaded-file
|
977
|
-
[uploading]: #uploading
|
978
1048
|
[uploader]: #uploader
|
979
1049
|
[validation]: #validation
|
980
1050
|
|
@@ -1042,3 +1112,4 @@ Shrine.logger.level = Logger::WARN
|
|
1042
1112
|
[storages]: https://shrinerb.com/docs/external/extensions#storages
|
1043
1113
|
[plugins]: https://shrinerb.com/plugins
|
1044
1114
|
[external plugins]: https://shrinerb.com/docs/external/extensions#plugins
|
1115
|
+
[gin index]: https://www.postgresql.org/docs/current/datatype-json.html#JSON-INDEXING
|