shrine 2.14.0 → 2.15.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of shrine might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +384 -374
- data/README.md +132 -63
- data/doc/advantages.md +191 -109
- data/doc/attacher.md +1 -1
- data/doc/carrierwave.md +4 -4
- data/doc/creating_storages.md +2 -2
- data/doc/design.md +2 -2
- data/doc/direct_s3.md +3 -3
- data/doc/metadata.md +1 -1
- data/doc/multiple_files.md +2 -2
- data/doc/paperclip.md +3 -3
- data/doc/plugins/activerecord.md +92 -0
- data/doc/plugins/add_metadata.md +93 -0
- data/doc/plugins/backgrounding.md +148 -0
- data/doc/plugins/backup.md +29 -0
- data/doc/plugins/cached_attachment_data.md +23 -0
- data/doc/plugins/copy.md +22 -0
- data/doc/plugins/data_uri.md +92 -0
- data/doc/plugins/default_storage.md +16 -0
- data/doc/plugins/default_url.md +33 -0
- data/doc/plugins/default_url_options.md +22 -0
- data/doc/plugins/delete_promoted.md +10 -0
- data/doc/plugins/delete_raw.md +16 -0
- data/doc/plugins/derivation_endpoint.md +747 -0
- data/doc/plugins/determine_mime_type.md +64 -0
- data/doc/plugins/direct_upload.md +170 -0
- data/doc/plugins/download_endpoint.md +83 -0
- data/doc/plugins/dynamic_storage.md +20 -0
- data/doc/plugins/hooks.md +56 -0
- data/doc/plugins/included.md +15 -0
- data/doc/plugins/infer_extension.md +57 -0
- data/doc/plugins/keep_files.md +20 -0
- data/doc/plugins/logging.md +39 -0
- data/doc/plugins/metadata_attribues.md +43 -0
- data/doc/plugins/migration_helpers.md +58 -0
- data/doc/plugins/module_include.md +40 -0
- data/doc/plugins/moving.md +17 -0
- data/doc/plugins/multi_delete.md +18 -0
- data/doc/plugins/parallelize.md +14 -0
- data/doc/plugins/parsed_json.md +9 -0
- data/doc/plugins/presign_endpoint.md +133 -0
- data/doc/plugins/pretty_location.md +29 -0
- data/doc/plugins/processing.md +68 -0
- data/doc/plugins/rack_file.md +49 -0
- data/doc/plugins/rack_response.md +96 -0
- data/doc/plugins/recache.md +27 -0
- data/doc/plugins/refresh_metadata.md +31 -0
- data/doc/plugins/remote_url.md +104 -0
- data/doc/plugins/remove_attachment.md +16 -0
- data/doc/plugins/remove_invalid.md +9 -0
- data/doc/plugins/restore_cached_data.md +14 -0
- data/doc/plugins/sequel.md +64 -0
- data/doc/plugins/signature.md +49 -0
- data/doc/plugins/store_dimensions.md +68 -0
- data/doc/plugins/tempfile.md +40 -0
- data/doc/plugins/upload_endpoint.md +123 -0
- data/doc/plugins/upload_options.md +28 -0
- data/doc/plugins/validation_helpers.md +129 -0
- data/doc/plugins/versions.md +179 -0
- data/doc/processing.md +217 -247
- data/doc/refile.md +3 -3
- data/doc/release_notes/1.0.0.md +143 -0
- data/doc/release_notes/1.1.0.md +184 -0
- data/doc/release_notes/1.2.0.md +37 -0
- data/doc/release_notes/1.3.0.md +90 -0
- data/doc/release_notes/1.4.0.md +167 -0
- data/doc/release_notes/1.4.1.md +9 -0
- data/doc/release_notes/1.4.2.md +20 -0
- data/doc/release_notes/2.0.0.md +173 -0
- data/doc/release_notes/2.0.1.md +12 -0
- data/doc/release_notes/2.1.0.md +59 -0
- data/doc/release_notes/2.1.1.md +8 -0
- data/doc/release_notes/2.10.0.md +52 -0
- data/doc/release_notes/2.10.1.md +6 -0
- data/doc/release_notes/2.11.0.md +69 -0
- data/doc/release_notes/2.12.0.md +65 -0
- data/doc/release_notes/2.13.0.md +146 -0
- data/doc/release_notes/2.14.0.md +278 -0
- data/doc/release_notes/2.15.0.md +82 -0
- data/doc/release_notes/2.2.0.md +98 -0
- data/doc/release_notes/2.3.0.md +50 -0
- data/doc/release_notes/2.3.1.md +10 -0
- data/doc/release_notes/2.4.0.md +87 -0
- data/doc/release_notes/2.4.1.md +29 -0
- data/doc/release_notes/2.5.0.md +130 -0
- data/doc/release_notes/2.6.0.md +254 -0
- data/doc/release_notes/2.6.1.md +14 -0
- data/doc/release_notes/2.7.0.md +180 -0
- data/doc/release_notes/2.8.0.md +95 -0
- data/doc/release_notes/2.9.0.md +82 -0
- data/doc/retrieving_uploads.md +1 -1
- data/doc/storage/file_system.md +96 -0
- data/doc/storage/s3.md +293 -0
- data/doc/validation.md +1 -1
- data/lib/shrine/plugins/_urlsafe_serialization.rb +33 -125
- data/lib/shrine/plugins/activerecord.rb +0 -78
- data/lib/shrine/plugins/add_metadata.rb +0 -80
- data/lib/shrine/plugins/backgrounding.rb +0 -134
- data/lib/shrine/plugins/backup.rb +0 -22
- data/lib/shrine/plugins/cached_attachment_data.rb +0 -15
- data/lib/shrine/plugins/copy.rb +0 -14
- data/lib/shrine/plugins/data_uri.rb +0 -73
- data/lib/shrine/plugins/default_storage.rb +0 -11
- data/lib/shrine/plugins/default_url.rb +0 -25
- data/lib/shrine/plugins/default_url_options.rb +0 -16
- data/lib/shrine/plugins/delete_promoted.rb +0 -6
- data/lib/shrine/plugins/delete_raw.rb +0 -10
- data/lib/shrine/plugins/derivation_endpoint.rb +652 -0
- data/lib/shrine/plugins/determine_mime_type.rb +1 -85
- data/lib/shrine/plugins/direct_upload.rb +0 -155
- data/lib/shrine/plugins/download_endpoint.rb +11 -73
- data/lib/shrine/plugins/dynamic_storage.rb +0 -17
- data/lib/shrine/plugins/hooks.rb +0 -48
- data/lib/shrine/plugins/included.rb +0 -12
- data/lib/shrine/plugins/infer_extension.rb +0 -49
- data/lib/shrine/plugins/keep_files.rb +0 -19
- data/lib/shrine/plugins/logging.rb +0 -39
- data/lib/shrine/plugins/metadata_attributes.rb +0 -35
- data/lib/shrine/plugins/migration_helpers.rb +0 -50
- data/lib/shrine/plugins/module_include.rb +0 -32
- data/lib/shrine/plugins/moving.rb +0 -12
- data/lib/shrine/plugins/multi_delete.rb +0 -13
- data/lib/shrine/plugins/parallelize.rb +0 -8
- data/lib/shrine/plugins/parsed_json.rb +0 -5
- data/lib/shrine/plugins/presign_endpoint.rb +2 -117
- data/lib/shrine/plugins/pretty_location.rb +0 -22
- data/lib/shrine/plugins/processing.rb +0 -55
- data/lib/shrine/plugins/rack_file.rb +0 -39
- data/lib/shrine/plugins/rack_response.rb +0 -81
- data/lib/shrine/plugins/recache.rb +0 -21
- data/lib/shrine/plugins/refresh_metadata.rb +0 -24
- data/lib/shrine/plugins/remote_url.rb +0 -85
- data/lib/shrine/plugins/remove_attachment.rb +0 -10
- data/lib/shrine/plugins/remove_invalid.rb +0 -6
- data/lib/shrine/plugins/restore_cached_data.rb +0 -10
- data/lib/shrine/plugins/sequel.rb +0 -54
- data/lib/shrine/plugins/signature.rb +0 -37
- data/lib/shrine/plugins/store_dimensions.rb +0 -63
- data/lib/shrine/plugins/tempfile.rb +4 -35
- data/lib/shrine/plugins/upload_endpoint.rb +2 -109
- data/lib/shrine/plugins/upload_options.rb +0 -20
- data/lib/shrine/plugins/validation_helpers.rb +0 -36
- data/lib/shrine/plugins/versions.rb +0 -156
- data/lib/shrine/storage/file_system.rb +0 -77
- data/lib/shrine/storage/s3.rb +0 -249
- data/lib/shrine/version.rb +1 -1
- data/shrine.gemspec +2 -2
- metadata +86 -6
@@ -0,0 +1,64 @@
|
|
1
|
+
# Determine MIME Type
|
2
|
+
|
3
|
+
The `determine_mime_type` plugin allows you to determine and store the actual
|
4
|
+
MIME type of the file analyzed from file content.
|
5
|
+
|
6
|
+
```rb
|
7
|
+
plugin :determine_mime_type
|
8
|
+
```
|
9
|
+
|
10
|
+
By default the UNIX [file] utility is used to determine the MIME type, and the
|
11
|
+
result is automatically written to the `mime_type` metadata field. You can
|
12
|
+
choose a different built-in MIME type analyzer:
|
13
|
+
|
14
|
+
```rb
|
15
|
+
plugin :determine_mime_type, analyzer: :marcel
|
16
|
+
```
|
17
|
+
|
18
|
+
The following analyzers are accepted:
|
19
|
+
|
20
|
+
| Name | Description |
|
21
|
+
| :------ | :----------- |
|
22
|
+
| `:file` | (Default). Uses the [file] utility to determine the MIME type from file contents. It is installed by default on most operating systems, but the [Windows equivalent] needs to be installed separately. |
|
23
|
+
| `:fastimage` | Uses the [fastimage] gem to determine the MIME type from file contents. Fastimage is optimized for speed over accuracy. Best used for image content. |
|
24
|
+
| `:filemagic` | Uses the [ruby-filemagic] gem to determine the MIME type from file contents, using a similar MIME database as the `file` utility. Unlike the `file` utility, ruby-filemagic works on Windows without any setup. |
|
25
|
+
| `:mimemagic` | Uses the [mimemagic] gem to determine the MIME type from file contents. Unlike ruby-filemagic, mimemagic is a pure-ruby solution, so it will work across all Ruby implementations. |
|
26
|
+
| `:marcel` | Uses the [marcel] gem to determine the MIME type from file contents. Marcel is Basecamp's wrapper around mimemagic, it adds priority logic (preferring magic over name when given both), some extra type definitions, and common type subclasses (including Keynote, Pages, etc). |
|
27
|
+
| `:mime_types` | Uses the [mime-types] gem to determine the MIME type from the file extension. Note that unlike other solutions, this analyzer is not guaranteed to return the actual MIME type of the file. |
|
28
|
+
| `:mini_mime` | Uses the [mini_mime] gem to determine the MIME type from the file extension. Note that unlike other solutions, this analyzer is not guaranteed to return the actual MIME type of the file. |
|
29
|
+
| `:content_type` | Retrieves the value of the `#content_type` attribute of the IO object. Note that this value normally comes from the "Content-Type" request header, so it's not guaranteed to hold the actual MIME type of the file. |
|
30
|
+
|
31
|
+
A single analyzer is not going to properly recognize all types of files, so you
|
32
|
+
can build your own custom analyzer for your requirements, where you can combine
|
33
|
+
the built-in analyzers. For example, if you want to correctly determine MIME
|
34
|
+
type of .css, .js, .json, .csv, .xml, or similar text-based files, you can
|
35
|
+
combine `file` and `mime_types` analyzers:
|
36
|
+
|
37
|
+
```rb
|
38
|
+
plugin :determine_mime_type, analyzer: -> (io, analyzers) do
|
39
|
+
mime_type = analyzers[:file].call(io)
|
40
|
+
mime_type = analyzers[:mime_types].call(io) if mime_type == "text/plain"
|
41
|
+
mime_type
|
42
|
+
end
|
43
|
+
```
|
44
|
+
|
45
|
+
You can also use methods for determining the MIME type directly:
|
46
|
+
|
47
|
+
```rb
|
48
|
+
# or YourUploader.determine_mime_type(io)
|
49
|
+
Shrine.determine_mime_type(io) # calls the defined analyzer
|
50
|
+
#=> "image/jpeg"
|
51
|
+
|
52
|
+
# or YourUploader.mime_type_analyzers
|
53
|
+
Shrine.mime_type_analyzers[:file].call(io) # calls a built-in analyzer
|
54
|
+
#=> "image/jpeg"
|
55
|
+
```
|
56
|
+
|
57
|
+
[file]: http://linux.die.net/man/1/file
|
58
|
+
[Windows equivalent]: http://gnuwin32.sourceforge.net/packages/file.htm
|
59
|
+
[ruby-filemagic]: https://github.com/blackwinter/ruby-filemagic
|
60
|
+
[mimemagic]: https://github.com/minad/mimemagic
|
61
|
+
[marcel]: https://github.com/basecamp/marcel
|
62
|
+
[mime-types]: https://github.com/mime-types/ruby-mime-types
|
63
|
+
[mini_mime]: https://github.com/discourse/mini_mime
|
64
|
+
[fastimage]: https://github.com/sdsykes/fastimage
|
@@ -0,0 +1,170 @@
|
|
1
|
+
# Direct Upload
|
2
|
+
|
3
|
+
*[OBSOLETE] This plugin is obsolete, you should use `upload_endpoint` or
|
4
|
+
`presign_endpoint` plugins instead.*
|
5
|
+
|
6
|
+
The `direct_upload` plugin provides a Rack endpoint which can be used for
|
7
|
+
uploading individual files asynchronously. It requires the [Roda] gem.
|
8
|
+
|
9
|
+
```rb
|
10
|
+
plugin :direct_upload
|
11
|
+
```
|
12
|
+
|
13
|
+
The Roda endpoint provides two routes:
|
14
|
+
|
15
|
+
* `POST /:storage/upload`
|
16
|
+
* `GET /:storage/presign`
|
17
|
+
|
18
|
+
This first route is for doing direct uploads to your app, the received file
|
19
|
+
will be uploaded the underlying storage. The second route is for doing direct
|
20
|
+
uploads to a 3rd-party service, it will return the URL where the file can be
|
21
|
+
uploaded to, along with the necessary request parameters.
|
22
|
+
|
23
|
+
This is how you can mount the endpoint in a Rails application:
|
24
|
+
|
25
|
+
```rb
|
26
|
+
Rails.application.routes.draw do
|
27
|
+
mount ImageUploader::UploadEndpoint => "/images"
|
28
|
+
end
|
29
|
+
```
|
30
|
+
|
31
|
+
Now your application will get `POST /images/cache/upload` and `GET
|
32
|
+
/images/cache/presign` routes. On the client side it is recommended to use
|
33
|
+
[Uppy] for uploading files to the app or directly to the 3rd-party service.
|
34
|
+
|
35
|
+
## Uploads
|
36
|
+
|
37
|
+
The upload route accepts a "file" query parameter, and returns the uploaded
|
38
|
+
file in JSON format:
|
39
|
+
|
40
|
+
```rb
|
41
|
+
# POST /images/cache/upload
|
42
|
+
{
|
43
|
+
"id": "43kewit94.jpg",
|
44
|
+
"storage": "cache",
|
45
|
+
"metadata": {
|
46
|
+
"size": 384393,
|
47
|
+
"filename": "nature.jpg",
|
48
|
+
"mime_type": "image/jpeg"
|
49
|
+
}
|
50
|
+
}
|
51
|
+
```
|
52
|
+
|
53
|
+
Once you've uploaded the file, you can assign the result to the hidden
|
54
|
+
attachment field in the form, or immediately send it to the server.
|
55
|
+
|
56
|
+
Note that the endpoint uploads the file standalone, without any knowledge of
|
57
|
+
the record, so `context[:record]` and `context[:name]` will be nil.
|
58
|
+
|
59
|
+
### Limiting filesize
|
60
|
+
|
61
|
+
It's good idea to limit the maximum filesize of uploaded files, if you set the
|
62
|
+
`:max_size` option, files which are too big will get automatically deleted and
|
63
|
+
413 status will be returned:
|
64
|
+
|
65
|
+
```rb
|
66
|
+
plugin :direct_upload, max_size: 5*1024*1024 # 5 MB
|
67
|
+
```
|
68
|
+
|
69
|
+
Note that this option doesn't affect presigned uploads, there you can apply
|
70
|
+
filesize limit when generating a presign. The filesize constraint here is for
|
71
|
+
security purposes, you should still perform file validations on attaching.
|
72
|
+
|
73
|
+
## Presigns
|
74
|
+
|
75
|
+
The presign route returns the URL to the 3rd-party service to which you can
|
76
|
+
upload the file, along with the necessary query parameters.
|
77
|
+
|
78
|
+
```rb
|
79
|
+
# GET /images/cache/presign
|
80
|
+
{
|
81
|
+
"url" => "https://my-bucket.s3-eu-west-1.amazonaws.com",
|
82
|
+
"fields" => {
|
83
|
+
"key" => "b7d575850ba61b44c8a9ff889dfdb14d88cdc25f8dd121004c8",
|
84
|
+
"policy" => "eyJleHBpcmF0aW9uIjoiMjAxNS0QwMToxMToyOVoiLCJjb2...",
|
85
|
+
"x-amz-credential" => "AKIAIJF55TMZYT6Q/20151024/eu-west-1/s3/aws4_request",
|
86
|
+
"x-amz-algorithm" => "AWS4-HMAC-SHA256",
|
87
|
+
"x-amz-date" => "20151024T001129Z",
|
88
|
+
"x-amz-signature" => "c1eb634f83f96b69bd675f535b3ff15ae184b102fcba51e4db5f4959b4ae26f4"
|
89
|
+
}
|
90
|
+
}
|
91
|
+
```
|
92
|
+
|
93
|
+
If you want that the generated location includes a file extension, you can
|
94
|
+
specify the `extension` query parameter: `GET
|
95
|
+
/:storage/presign?extension=.png`.
|
96
|
+
|
97
|
+
You can also completely change how the key is generated, with
|
98
|
+
`:presign_location`:
|
99
|
+
|
100
|
+
```rb
|
101
|
+
plugin :direct_upload, presign_location: -> (request) { "${filename}" }
|
102
|
+
```
|
103
|
+
|
104
|
+
This presign route internally calls `#presign` on the storage, and many
|
105
|
+
storages accept additional service-specific options. You can generate these
|
106
|
+
additional options per-request through `:presign_options`:
|
107
|
+
|
108
|
+
```rb
|
109
|
+
plugin :direct_upload, presign_options: { acl: "public-read" }
|
110
|
+
|
111
|
+
plugin :direct_upload, presign_options: ->(request) do
|
112
|
+
filename = request.params["filename"]
|
113
|
+
content_type = Rack::Mime.mime_type(File.extname(filename))
|
114
|
+
|
115
|
+
{
|
116
|
+
content_length_range: 0..(10*1024*1024), # limit filesize to 10MB
|
117
|
+
content_disposition: "attachment; filename=\"#{filename}\"", # download with original filename
|
118
|
+
content_type: content_type, # set correct content type
|
119
|
+
}
|
120
|
+
end
|
121
|
+
```
|
122
|
+
|
123
|
+
Both `:presign_location` and `:presign_options` in their block versions are
|
124
|
+
yielded an instance of [Roda request], which is a subclass of `Rack::Request`.
|
125
|
+
|
126
|
+
See the [Direct Uploads to S3] guide for further instructions on how to hook
|
127
|
+
the presigned uploads to a form.
|
128
|
+
|
129
|
+
## Allowed storages
|
130
|
+
|
131
|
+
By default only uploads to `:cache` are allowed, to prevent the possibility of
|
132
|
+
having orphan files in your main storage. But you can allow more storages:
|
133
|
+
|
134
|
+
```rb
|
135
|
+
plugin :direct_upload, allowed_storages: [:cache, :store]
|
136
|
+
```
|
137
|
+
|
138
|
+
## Customizing endpoint
|
139
|
+
|
140
|
+
Since the endpoint is a [Roda] app, it is very customizable. For example, you
|
141
|
+
can add a Rack middleware to change the response status and headers:
|
142
|
+
|
143
|
+
```rb
|
144
|
+
class ShrineUploadMiddleware
|
145
|
+
def initialize(app)
|
146
|
+
@app = app
|
147
|
+
end
|
148
|
+
|
149
|
+
def call(env)
|
150
|
+
result = @app.call(env)
|
151
|
+
|
152
|
+
if result[0] == 200 && env["PATH_INFO"].end_with?("upload")
|
153
|
+
result[0] = 201
|
154
|
+
result[1]["Location"] = Shrine.uploaded_file(result[2].first).url
|
155
|
+
end
|
156
|
+
|
157
|
+
result
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
Shrine::UploadEndpoint.use ShrineUploadMiddleware
|
162
|
+
```
|
163
|
+
|
164
|
+
Upon subclassing uploader the upload endpoint is also subclassed. You can also
|
165
|
+
call the plugin again in an uploader subclass to change its configuration.
|
166
|
+
|
167
|
+
[Roda]: https://github.com/jeremyevans/roda
|
168
|
+
[Uppy]: https://uppy.io
|
169
|
+
[Roda request]: http://roda.jeremyevans.net/rdoc/classes/Roda/RodaPlugins/Base/RequestMethods.html
|
170
|
+
[Direct Uploads to S3]: /doc/direct_s3.md#readme
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# Download Endpoint
|
2
|
+
|
3
|
+
The `download_endpoint` plugin provides a Rack app for downloading uploaded
|
4
|
+
files from specified storages. This can be useful when files from your storage
|
5
|
+
isn't accessible over URL (e.g. database storages) or if you want to
|
6
|
+
authenticate your downloads. It requires the [Roda] gem.
|
7
|
+
|
8
|
+
```rb
|
9
|
+
# Gemfile
|
10
|
+
gem "roda" # dependency of the download_endpoint plugin
|
11
|
+
```
|
12
|
+
|
13
|
+
You can configure the plugin with the path prefix which the endpoint will be
|
14
|
+
mounted on.
|
15
|
+
|
16
|
+
```rb
|
17
|
+
plugin :download_endpoint, prefix: "attachments"
|
18
|
+
```
|
19
|
+
|
20
|
+
The endpoint should then be mounted on the specified prefix:
|
21
|
+
|
22
|
+
```rb
|
23
|
+
# config.ru (Rack)
|
24
|
+
map "/attachments" do
|
25
|
+
run Shrine.download_endpoint
|
26
|
+
end
|
27
|
+
|
28
|
+
# OR
|
29
|
+
|
30
|
+
# config/routes.rb (Rails)
|
31
|
+
Rails.application.routes.draw do
|
32
|
+
mount Shrine.download_endpoint => "/attachments"
|
33
|
+
end
|
34
|
+
```
|
35
|
+
|
36
|
+
Any uploaded file can be downloaded through this endpoint. When a file is
|
37
|
+
requested, its content will be efficiently streamed from the storage into the
|
38
|
+
response body.
|
39
|
+
|
40
|
+
Links to the download endpoint are generated by calling
|
41
|
+
`UploadedFile#download_url` instead of the usual `UploadedFile#url`.
|
42
|
+
|
43
|
+
```rb
|
44
|
+
uploaded_file.download_url #=> "/attachments/eyJpZCI6ImFkdzlyeTM..."
|
45
|
+
```
|
46
|
+
|
47
|
+
## Host
|
48
|
+
|
49
|
+
You can specify download URL host via the `:host` plugin option:
|
50
|
+
|
51
|
+
```rb
|
52
|
+
plugin :download_endpoint, host: "http://example.com"
|
53
|
+
```
|
54
|
+
|
55
|
+
or by passing `:host` to `UploadedFile#download_url`:
|
56
|
+
|
57
|
+
```rb
|
58
|
+
uploaded_file.download_url(host: "http://example.com")
|
59
|
+
#=> "http//example.com/attachments/eyJpZCI6ImFkdzlyeTM..."
|
60
|
+
```
|
61
|
+
|
62
|
+
## Performance considerations
|
63
|
+
|
64
|
+
Streaming files through the app might impact the request throughput, depending
|
65
|
+
on the web server you're using. So it's recommended to use a CDN, which can be
|
66
|
+
set via the `:host` option.
|
67
|
+
|
68
|
+
Alternatively, you can have the endpoint redirect to the direct file URL:
|
69
|
+
|
70
|
+
```rb
|
71
|
+
plugin :download_endpoint, redirect: true
|
72
|
+
# or
|
73
|
+
plugin :download_endpoint, redirect: -> (uploaded_file, request) do
|
74
|
+
# return URL which the request will redirect to
|
75
|
+
end
|
76
|
+
```
|
77
|
+
|
78
|
+
## Custom endpoint
|
79
|
+
|
80
|
+
If you want to have more control on download requests, you can use the
|
81
|
+
`rack_response` plugin which this plugin uses internally.
|
82
|
+
|
83
|
+
[Roda]: https://github.com/jeremyevans/roda
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# Dynamic Storage
|
2
|
+
|
3
|
+
The `dynamic_storage` plugin allows you to register a storage using a regex,
|
4
|
+
and evaluate the storage class dynamically depending on the regex.
|
5
|
+
|
6
|
+
Example:
|
7
|
+
|
8
|
+
```rb
|
9
|
+
plugin :dynamic_storage
|
10
|
+
|
11
|
+
storage /store_(\w+)/ do |match|
|
12
|
+
Shrine::Storages::S3.new(bucket: match[1])
|
13
|
+
end
|
14
|
+
```
|
15
|
+
|
16
|
+
The above example uses S3 storage where the bucket name depends on the storage
|
17
|
+
name suffix. For example, `:store_foo` will use S3 storage which saves files to
|
18
|
+
the bucket "foo". The block is yielded an instance of `MatchData`.
|
19
|
+
|
20
|
+
This can be useful in combination with the `default_storage` plugin.
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# Hooks
|
2
|
+
|
3
|
+
The `hooks` plugin allows you to trigger some code around
|
4
|
+
processing/storing/deleting of each file.
|
5
|
+
|
6
|
+
```rb
|
7
|
+
plugin :hooks
|
8
|
+
```
|
9
|
+
|
10
|
+
Shrine uses instance methods for hooks. To define a hook for an uploader, you
|
11
|
+
just add an instance method to the uploader:
|
12
|
+
|
13
|
+
```rb
|
14
|
+
class ImageUploader < Shrine
|
15
|
+
def around_process(io, context)
|
16
|
+
super
|
17
|
+
rescue
|
18
|
+
ExceptionNotifier.processing_failed(io, context)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
```
|
22
|
+
|
23
|
+
Each hook will be called with 2 arguments, `io` and `context`. You should
|
24
|
+
always call `super` when overriding a hook, as other plugins may be using hooks
|
25
|
+
internally, and without `super` those wouldn't get executed.
|
26
|
+
|
27
|
+
Shrine calls hooks in the following order when uploading a file:
|
28
|
+
|
29
|
+
* `before_upload`
|
30
|
+
* `around_upload`
|
31
|
+
- `before_process`
|
32
|
+
- `around_process`
|
33
|
+
- `after_process`
|
34
|
+
- `before_store`
|
35
|
+
- `around_store`
|
36
|
+
- `after_store`
|
37
|
+
* `after_upload`
|
38
|
+
|
39
|
+
Shrine calls hooks in the following order when deleting a file:
|
40
|
+
|
41
|
+
* `before_delete`
|
42
|
+
* `around_delete`
|
43
|
+
* `after_delete`
|
44
|
+
|
45
|
+
By default every `around_*` hook returns the result of the corresponding
|
46
|
+
operation:
|
47
|
+
|
48
|
+
```rb
|
49
|
+
class ImageUploader < Shrine
|
50
|
+
def around_store(io, context)
|
51
|
+
result = super
|
52
|
+
result.class #=> Shrine::UploadedFile
|
53
|
+
result # it's good to always return the result for consistent behaviour
|
54
|
+
end
|
55
|
+
end
|
56
|
+
```
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# Included
|
2
|
+
|
3
|
+
The `included` plugin allows you to hook up to the `.included` hook of the
|
4
|
+
attachment module, and call additional methods on the model which includes it.
|
5
|
+
|
6
|
+
```rb
|
7
|
+
plugin :included do |name|
|
8
|
+
before_save do
|
9
|
+
# ...
|
10
|
+
end
|
11
|
+
end
|
12
|
+
```
|
13
|
+
|
14
|
+
If you want to define additional methods on the model, it's recommended to use
|
15
|
+
the `module_include` plugin instead.
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# Infer Extension
|
2
|
+
|
3
|
+
The `infer_extension` plugin allows deducing the appropriate file extension for
|
4
|
+
the upload location based on the MIME type of the file. This is useful when
|
5
|
+
using `data_uri` and `remote_url` plugins, where the file extension might not
|
6
|
+
be known.
|
7
|
+
|
8
|
+
```rb
|
9
|
+
plugin :infer_extension
|
10
|
+
```
|
11
|
+
|
12
|
+
Ordinarily, the upload location will gain the inferred extension only if it
|
13
|
+
couldn't be determined from the filename. However, you can pass `force: true`
|
14
|
+
to force the inferred extension to be used rather than an extension from the
|
15
|
+
original filename. This can be used to canonicalize extensions (jpg, jpeg =>
|
16
|
+
jpeg), or replace an incorrect original extension.
|
17
|
+
|
18
|
+
```rb
|
19
|
+
plugin :infer_extension, force: true
|
20
|
+
```
|
21
|
+
|
22
|
+
By default `MIME::Types` will be used for inferring the extension, but you can
|
23
|
+
also choose a different inferrer:
|
24
|
+
|
25
|
+
```rb
|
26
|
+
plugin :infer_extension, inferrer: :mini_mime
|
27
|
+
```
|
28
|
+
|
29
|
+
The following inferrers are accepted:
|
30
|
+
|
31
|
+
| Name | Description |
|
32
|
+
| :------------ | :----------- |
|
33
|
+
| `:mime_types` | (Default). Uses the [mime-types] gem to infer the appropriate extension from MIME type. |
|
34
|
+
| `:mini_mime` | Uses the [mini_mime] gem to infer the appropriate extension from MIME type. |
|
35
|
+
|
36
|
+
You can also define your own inferrer, with the possibility to call the
|
37
|
+
built-in inferrers:
|
38
|
+
|
39
|
+
```rb
|
40
|
+
plugin :infer_extension, inferrer: -> (mime_type, inferrers) do
|
41
|
+
# don't add extension if the file is a text file
|
42
|
+
inferrers[:rack_mime].call(mime_type) unless mime_type == "text/plain"
|
43
|
+
end
|
44
|
+
```
|
45
|
+
|
46
|
+
You can also use methods for inferring extension directly:
|
47
|
+
|
48
|
+
```rb
|
49
|
+
Shrine.infer_extension("image/jpeg")
|
50
|
+
# => ".jpeg"
|
51
|
+
|
52
|
+
Shrine.extension_inferrers[:mime_types].call("image/jpeg")
|
53
|
+
# => ".jpeg"
|
54
|
+
```
|
55
|
+
|
56
|
+
[mime-types]: https://github.com/mime-types/ruby-mime-types
|
57
|
+
[mini_mime]: https://github.com/discourse/mini_mime
|