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,20 @@
|
|
1
|
+
# Keep Files
|
2
|
+
|
3
|
+
The `keep_files` plugin gives you the ability to prevent files from being
|
4
|
+
deleted. This functionality is useful when implementing soft deletes, or when
|
5
|
+
implementing some kind of [event store] where you need to track history.
|
6
|
+
|
7
|
+
The plugin accepts the following options:
|
8
|
+
|
9
|
+
| Option | Description |
|
10
|
+
| :------ | :---------- |
|
11
|
+
| `:destroyed` | If set to `true`, destroying the record won't delete the associated attachment. |
|
12
|
+
| `:replaced` | If set to `true`, uploading a new attachment won't delete the old one. |
|
13
|
+
|
14
|
+
For example, the following will keep destroyed and replaced files:
|
15
|
+
|
16
|
+
```rb
|
17
|
+
plugin :keep_files, destroyed: true, replaced: true
|
18
|
+
```
|
19
|
+
|
20
|
+
[event store]: http://docs.geteventstore.com/introduction/event-sourcing-basics/
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# Logging
|
2
|
+
|
3
|
+
The `logging` plugin logs any storing/processing/deleting that is performed.
|
4
|
+
|
5
|
+
```rb
|
6
|
+
plugin :logging
|
7
|
+
```
|
8
|
+
|
9
|
+
This plugin is useful when you want to have overview of what exactly is going
|
10
|
+
on, or you simply want to have it logged for future debugging. By default the
|
11
|
+
logging output looks something like this:
|
12
|
+
|
13
|
+
```
|
14
|
+
2015-10-09T20:06:06.676Z #25602: STORE[cache] ImageUploader[:avatar] User[29543] 1 file (0.1s)
|
15
|
+
2015-10-09T20:06:06.854Z #25602: PROCESS[store]: ImageUploader[:avatar] User[29543] 1-3 files (0.22s)
|
16
|
+
2015-10-09T20:06:07.133Z #25602: DELETE[destroyed]: ImageUploader[:avatar] User[29543] 3 files (0.07s)
|
17
|
+
```
|
18
|
+
|
19
|
+
The plugin accepts the following options:
|
20
|
+
|
21
|
+
| Option | Description |
|
22
|
+
| :-------- | :---------- |
|
23
|
+
| `:format` | This allows you to change the logging output into something that may be easier to grep. Accepts `:human` (default), `:json` and `:logfmt`. |
|
24
|
+
| `:stream` | The default logging stream is `$stdout`, but you may want to change it, e.g. if you log into a file. This option is passed directly to `Logger.new` (from the "logger" Ruby standard library). |
|
25
|
+
| `:logger` | This allows you to change the logger entirely. This is useful for example in Rails applications, where you might want to assign this option to `Rails.logger`. |
|
26
|
+
|
27
|
+
The default format is probably easiest to read, but may not be easiest to grep.
|
28
|
+
If this is important to you, you can switch to another format:
|
29
|
+
|
30
|
+
```rb
|
31
|
+
plugin :logging, format: :json
|
32
|
+
# {"action":"upload","phase":"cache","uploader":"ImageUploader","attachment":"avatar",...}
|
33
|
+
|
34
|
+
plugin :logging, format: :logfmt
|
35
|
+
# action=upload phase=cache uploader=ImageUploader attachment=avatar record_class=User ...
|
36
|
+
```
|
37
|
+
|
38
|
+
Logging is by default disabled in tests, but you can enable it by setting
|
39
|
+
`Shrine.logger.level = Logger::INFO`.
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# Metadata Attributes
|
2
|
+
|
3
|
+
The `metadata_attributes` plugin allows you to sync attachment metadata to
|
4
|
+
additional record attributes. You can provide a hash of mappings to the plugin
|
5
|
+
call itself or the `Attacher.metadata_attributes` method:
|
6
|
+
|
7
|
+
```rb
|
8
|
+
plugin :metadata_attributes, :size => :size, :mime_type => :type
|
9
|
+
# or
|
10
|
+
plugin :metadata_attributes
|
11
|
+
Attacher.metadata_attributes :size => :size, :mime_type => :type
|
12
|
+
```
|
13
|
+
|
14
|
+
The above configuration will sync `size` metadata field to `<attachment>_size`
|
15
|
+
record attribute, and `mime_type` metadata field to `<attachment>_type` record
|
16
|
+
attribute.
|
17
|
+
|
18
|
+
```rb
|
19
|
+
user.avatar = image
|
20
|
+
user.avatar.metadata["size"] #=> 95724
|
21
|
+
user.avatar_size #=> 95724
|
22
|
+
user.avatar.metadata["mime_type"] #=> "image/jpeg"
|
23
|
+
user.avatar_type #=> "image/jpeg"
|
24
|
+
|
25
|
+
user.avatar = nil
|
26
|
+
user.avatar_size #=> nil
|
27
|
+
user.avatar_type #=> nil
|
28
|
+
```
|
29
|
+
|
30
|
+
If you want to specify the full record attribute name, pass the record
|
31
|
+
attribute name as a string instead of a symbol.
|
32
|
+
|
33
|
+
```rb
|
34
|
+
Attacher.metadata_attributes :filename => "original_filename"
|
35
|
+
|
36
|
+
# ...
|
37
|
+
|
38
|
+
photo.image = image
|
39
|
+
photo.original_filename #=> "nature.jpg"
|
40
|
+
```
|
41
|
+
|
42
|
+
If any corresponding metadata attribute doesn't exist on the record, that
|
43
|
+
metadata sync will be silently skipped.
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# Migration Helpers
|
2
|
+
|
3
|
+
The migration_helpers plugin gives the attacher additional helper methods which
|
4
|
+
are convenient when doing file migrations.
|
5
|
+
|
6
|
+
The plugin also allows convenient delegating to these methods through the
|
7
|
+
model, by setting `:delegate`:
|
8
|
+
|
9
|
+
```rb
|
10
|
+
plugin :migration_helpers, delegate: true
|
11
|
+
```
|
12
|
+
|
13
|
+
## `update_stored`
|
14
|
+
|
15
|
+
This method updates the record's attachment with the result of the given block.
|
16
|
+
|
17
|
+
```rb
|
18
|
+
user.avatar_attacher.update_stored do |avatar|
|
19
|
+
user.avatar_attacher.store.upload(avatar) # saved to the record
|
20
|
+
end
|
21
|
+
|
22
|
+
# with model delegation
|
23
|
+
user.update_avatar do |avatar|
|
24
|
+
user.avatar_store.upload(avatar) # saved to the record
|
25
|
+
end
|
26
|
+
```
|
27
|
+
|
28
|
+
The block will get triggered _only_ if the attachment is present and not
|
29
|
+
cached, *and* will save the record only if the record's attachment hasn't
|
30
|
+
changed in the time it took to execute the block. This method is most useful
|
31
|
+
for adding/removing versions and changing locations of files.
|
32
|
+
|
33
|
+
## `cached?` and `stored?`
|
34
|
+
|
35
|
+
These methods return true if attachment exists and is cached/stored:
|
36
|
+
|
37
|
+
```rb
|
38
|
+
user.avatar_attacher.cached? # user.avatar && user.avatar_attacher.cache.uploaded?(user.avatar)
|
39
|
+
user.avatar_attacher.stored? # user.avatar && user.avatar_attacher.store.uploaded?(user.avatar)
|
40
|
+
|
41
|
+
# with model delegation
|
42
|
+
user.avatar_cached?
|
43
|
+
user.avatar_stored?
|
44
|
+
```
|
45
|
+
|
46
|
+
## `attachment_cache` and `attachment_store`
|
47
|
+
|
48
|
+
These methods return cache and store uploaders used by the underlying attacher:
|
49
|
+
|
50
|
+
```rb
|
51
|
+
# these methods already exist without migration_helpers
|
52
|
+
user.avatar_attacher.cache #=> #<Shrine @storage_key=:cache @storage=#<Shrine::Storage::FileSystem @directory=public/uploads>>
|
53
|
+
user.avatar_attacher.store #=> #<Shrine @storage_key=:store @storage=#<Shrine::Storage::S3:0x007fb8343397c8 @bucket=#<Aws::S3::Bucket name="foo">>>
|
54
|
+
|
55
|
+
# with model delegation
|
56
|
+
user.avatar_cache
|
57
|
+
user.avatar_store
|
58
|
+
```
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# Module Include
|
2
|
+
|
3
|
+
The `module_include` plugin allows you to extend Shrine's core classes for the
|
4
|
+
given uploader with modules/methods.
|
5
|
+
|
6
|
+
```rb
|
7
|
+
plugin :module_include
|
8
|
+
```
|
9
|
+
|
10
|
+
To add a module to a core class, call the appropriate method:
|
11
|
+
|
12
|
+
```rb
|
13
|
+
attachment_module CustomAttachmentMethods
|
14
|
+
attacher_module CustomAttacherMethods
|
15
|
+
file_module CustomFileMethods
|
16
|
+
```
|
17
|
+
|
18
|
+
Alternatively you can pass in a block (which internally creates a module):
|
19
|
+
|
20
|
+
```rb
|
21
|
+
attachment_module do
|
22
|
+
def included(model)
|
23
|
+
super
|
24
|
+
|
25
|
+
name = attachment_name
|
26
|
+
|
27
|
+
define_method :"#{name}_size" do |version|
|
28
|
+
attachment = send(name)
|
29
|
+
if attachment.is_a?(Hash)
|
30
|
+
attachment[version].size
|
31
|
+
elsif attachment
|
32
|
+
attachment.size
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
```
|
38
|
+
|
39
|
+
The above defines an additional `#<attachment>_size` method on the attachment
|
40
|
+
module, which is what is included in your model.
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# Moving
|
2
|
+
|
3
|
+
The `moving` plugin will *move* files to storages instead of copying them, when
|
4
|
+
the storage supports it. For FileSystem this will issue a `mv` command, which
|
5
|
+
is instantaneous regardless of the filesize, so in that case loading this
|
6
|
+
plugin can significantly speed up the attachment process.
|
7
|
+
|
8
|
+
```rb
|
9
|
+
plugin :moving
|
10
|
+
```
|
11
|
+
|
12
|
+
By default files will be moved whenever the storage supports it. If you want
|
13
|
+
moving to happen only for certain storages, you can set `:storages`:
|
14
|
+
|
15
|
+
```rb
|
16
|
+
plugin :moving, storages: [:cache]
|
17
|
+
```
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# Multi Delete
|
2
|
+
|
3
|
+
The `multi_delete` plugins allows you to leverage your storage's multi delete
|
4
|
+
capabilities.
|
5
|
+
|
6
|
+
```rb
|
7
|
+
plugin :multi_delete
|
8
|
+
```
|
9
|
+
|
10
|
+
This plugin allows you pass an array of files to `Shrine#delete`.
|
11
|
+
|
12
|
+
```rb
|
13
|
+
uploader.delete([file1, file2, file3])
|
14
|
+
```
|
15
|
+
|
16
|
+
Now if you're using Storage::S3, deleting an array of files will issue a single
|
17
|
+
HTTP request. Some other storages may support multi deletes as well. The
|
18
|
+
`versions` plugin uses this plugin for deleting multiple versions at once.
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# Parallelize
|
2
|
+
|
3
|
+
The `parallelize` plugin parallelizes uploads and deletes of multiple versions
|
4
|
+
using threads.
|
5
|
+
|
6
|
+
```rb
|
7
|
+
plugin :parallelize
|
8
|
+
```
|
9
|
+
|
10
|
+
By default a pool of 3 threads will be used, but you can change that:
|
11
|
+
|
12
|
+
```rb
|
13
|
+
plugin :parallelize, threads: 5
|
14
|
+
```
|
@@ -0,0 +1,133 @@
|
|
1
|
+
# Presign Endpoint
|
2
|
+
|
3
|
+
The `presign_endpoint` plugin provides a Rack endpoint which generates the URL,
|
4
|
+
fields, and headers that can be used to upload files directly to a storage
|
5
|
+
service. On the client side it's recommended to use [Uppy] for asynchronous
|
6
|
+
uploads. Storage services that support direct uploads include [Amazon S3],
|
7
|
+
[Google Cloud Storage], [Microsoft Azure Storage] and more.
|
8
|
+
|
9
|
+
```rb
|
10
|
+
plugin :presign_endpoint
|
11
|
+
```
|
12
|
+
|
13
|
+
The plugin adds a `Shrine.presign_endpoint` method which, given a storage
|
14
|
+
identifier, returns a Rack application that accepts GET requests and generates
|
15
|
+
a presign for the specified storage. You can run this Rack application inside
|
16
|
+
your app:
|
17
|
+
|
18
|
+
```rb
|
19
|
+
# config.ru (Rack)
|
20
|
+
map "/images/presign" do
|
21
|
+
run ImageUploader.presign_endpoint(:cache)
|
22
|
+
end
|
23
|
+
|
24
|
+
# OR
|
25
|
+
|
26
|
+
# config/routes.rb (Rails)
|
27
|
+
Rails.application.routes.draw do
|
28
|
+
mount ImageUploader.presign_endpoint(:cache) => "/images/presign"
|
29
|
+
end
|
30
|
+
```
|
31
|
+
|
32
|
+
Asynchronous upload is typically meant to replace the caching phase in the
|
33
|
+
default synchronous workflow, so we want to generate parameters for uploads to
|
34
|
+
the temporary (`:cache`) storage.
|
35
|
+
|
36
|
+
The above will create a `GET /images/presign` endpoint, which calls `#presign`
|
37
|
+
on the storage and returns the HTTP verb, URL, params, and headers needed for a
|
38
|
+
single upload directly to the storage service, in JSON format.
|
39
|
+
|
40
|
+
```rb
|
41
|
+
# GET /images/presign
|
42
|
+
{
|
43
|
+
"method": "post",
|
44
|
+
"url": "https://my-bucket.s3-eu-west-1.amazonaws.com",
|
45
|
+
"fields": {
|
46
|
+
"key": "b7d575850ba61b44c8a9ff889dfdb14d88cdc25f8dd121004c8",
|
47
|
+
"policy": "eyJleHBpcmF0aW9uIjoiMjAxNS0QwMToxMToyOVoiLCJjb25kaXRpb25zIjpbeyJidWNrZXQiOiJ...",
|
48
|
+
"x-amz-credential": "AKIAIJF55TMZYT6Q/20151024/eu-west-1/s3/aws4_request",
|
49
|
+
"x-amz-algorithm": "AWS4-HMAC-SHA256",
|
50
|
+
"x-amz-date": "20151024T001129Z",
|
51
|
+
"x-amz-signature": "c1eb634f83f96b69bd675f535b3ff15ae184b102fcba51e4db5f4959b4ae26f4"
|
52
|
+
},
|
53
|
+
"headers": {}
|
54
|
+
}
|
55
|
+
```
|
56
|
+
|
57
|
+
## Location
|
58
|
+
|
59
|
+
By default the generated location won't have any file extension, but you can
|
60
|
+
specify one by sending the `filename` query parameter:
|
61
|
+
|
62
|
+
```
|
63
|
+
GET /images/presign?filename=nature.jpg
|
64
|
+
```
|
65
|
+
|
66
|
+
It's also possible to customize how the presign location is generated:
|
67
|
+
|
68
|
+
```rb
|
69
|
+
plugin :presign_endpoint, presign_location: -> (request) do
|
70
|
+
"#{SecureRandom.hex}/#{request.params["filename"]}"
|
71
|
+
end
|
72
|
+
```
|
73
|
+
|
74
|
+
## Options
|
75
|
+
|
76
|
+
Some storages accept additional presign options, which you can pass in via
|
77
|
+
`:presign_options`, here is an example for S3 storage:
|
78
|
+
|
79
|
+
```rb
|
80
|
+
plugin :presign_endpoint, presign_options: -> (request) do
|
81
|
+
# Uppy will send the "filename" and "type" query parameters
|
82
|
+
filename = request.params["filename"]
|
83
|
+
type = request.params["type"]
|
84
|
+
|
85
|
+
{
|
86
|
+
content_length_range: 0..(10*1024*1024), # limit filesize to 10MB
|
87
|
+
content_disposition: ContentDisposition.inline(filename), # download with original filename
|
88
|
+
content_type: type, # set correct content type
|
89
|
+
}
|
90
|
+
end
|
91
|
+
```
|
92
|
+
|
93
|
+
The example above uses the [content_disposition] gem to correctly format the
|
94
|
+
`Content-Disposition` header value.
|
95
|
+
|
96
|
+
The `:presign_options` can be a Proc or a Hash.
|
97
|
+
|
98
|
+
## Presign
|
99
|
+
|
100
|
+
You can also customize how the presign itself is generated via the `:presign`
|
101
|
+
option:
|
102
|
+
|
103
|
+
```rb
|
104
|
+
plugin :presign_endpoint, presign: -> (id, options, request) do
|
105
|
+
# return a Hash with :url, :fields, and :headers keys
|
106
|
+
end
|
107
|
+
```
|
108
|
+
|
109
|
+
## Response
|
110
|
+
|
111
|
+
The response returned by the endpoint can be customized via the
|
112
|
+
`:rack_response` option:
|
113
|
+
|
114
|
+
```rb
|
115
|
+
plugin :presign_endpoint, rack_response: -> (data, request) do
|
116
|
+
body = { endpoint: data[:url], params: data[:fields], headers: data[:headers] }.to_json
|
117
|
+
[201, { "Content-Type" => "application/json" }, [body]]
|
118
|
+
end
|
119
|
+
```
|
120
|
+
|
121
|
+
## Ad-hoc options
|
122
|
+
|
123
|
+
You can override any of the options above when creating the endpoint:
|
124
|
+
|
125
|
+
```rb
|
126
|
+
Shrine.presign_endpoint(:cache, presign_location: "${filename}")
|
127
|
+
```
|
128
|
+
|
129
|
+
[Uppy]: https://uppy.io
|
130
|
+
[Amazon S3]: https://aws.amazon.com/s3/
|
131
|
+
[Google Cloud Storage]: https://cloud.google.com/storage/
|
132
|
+
[Microsoft Azure Storage]: https://azure.microsoft.com/en-us/services/storage/
|
133
|
+
[content_disposition]: https://github.com/shrinerb/content_disposition
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# Pretty Location
|
2
|
+
|
3
|
+
The `pretty_location` plugin attempts to generate a nicer folder structure for
|
4
|
+
uploaded files.
|
5
|
+
|
6
|
+
```rb
|
7
|
+
plugin :pretty_location
|
8
|
+
```
|
9
|
+
|
10
|
+
This plugin uses the context information from the Attacher to try to generate a
|
11
|
+
nested folder structure which separates files for each record. The newly
|
12
|
+
generated locations will typically look like this:
|
13
|
+
|
14
|
+
```rb
|
15
|
+
"user/564/avatar/thumb-493g82jf23.jpg"
|
16
|
+
# :model/:id/:attachment/:version-:uid.:extension
|
17
|
+
```
|
18
|
+
|
19
|
+
By default if a record class is inside a namespace, only the "inner" class name
|
20
|
+
is used in the location. If you want to include the namespace, you can pass in
|
21
|
+
the `:namespace` option with the desired separator as the value:
|
22
|
+
|
23
|
+
```rb
|
24
|
+
plugin :pretty_location, namespace: "_"
|
25
|
+
# "blog_user/.../493g82jf23.jpg"
|
26
|
+
|
27
|
+
plugin :pretty_location, namespace: "/"
|
28
|
+
# "blog/user/.../493g82jf23.jpg"
|
29
|
+
```
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# Processing
|
2
|
+
|
3
|
+
Shrine uploaders can define the `#process` method, which will get called
|
4
|
+
whenever a file is uploaded. It is given the original file, and is expected to
|
5
|
+
return the processed files.
|
6
|
+
|
7
|
+
```rb
|
8
|
+
def process(io, context)
|
9
|
+
# you can process the original file `io` and return processed file(s)
|
10
|
+
end
|
11
|
+
```
|
12
|
+
|
13
|
+
However, when handling files as attachments, the same file is uploaded to
|
14
|
+
temporary and permanent storage. Since we only want to apply the same
|
15
|
+
processing once, we need to branch based on the context.
|
16
|
+
|
17
|
+
```rb
|
18
|
+
def process(io, context)
|
19
|
+
if context[:action] == :store # promote phase
|
20
|
+
# ...
|
21
|
+
end
|
22
|
+
end
|
23
|
+
```
|
24
|
+
|
25
|
+
The `processing` plugin simplifies this by allowing us to declaratively define
|
26
|
+
file processing for specified actions.
|
27
|
+
|
28
|
+
```rb
|
29
|
+
plugin :processing
|
30
|
+
|
31
|
+
process(:store) do |io, context|
|
32
|
+
# ...
|
33
|
+
end
|
34
|
+
```
|
35
|
+
|
36
|
+
An example of resizing an image using the [image_processing] library:
|
37
|
+
|
38
|
+
```rb
|
39
|
+
require "image_processing/mini_magick"
|
40
|
+
|
41
|
+
process(:store) do |io, context|
|
42
|
+
io.download do |original|
|
43
|
+
ImageProcessing::MiniMagick
|
44
|
+
.source(original)
|
45
|
+
.resize_to_limit!(800, 800)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
```
|
49
|
+
|
50
|
+
The declarations are additive and inheritable, so for the same action you can
|
51
|
+
declare multiple blocks, and they will be performed in the same order, with
|
52
|
+
output from previous block being the input to next.
|
53
|
+
|
54
|
+
## Manually Run Processing
|
55
|
+
|
56
|
+
You can manually trigger the defined processing via the uploader by calling
|
57
|
+
`#upload` or `#process` and setting `:action` to the name of your processing
|
58
|
+
block:
|
59
|
+
|
60
|
+
```rb
|
61
|
+
uploader.upload(file, action: :store) # process and upload
|
62
|
+
uploader.process(file, action: :store) # only process
|
63
|
+
```
|
64
|
+
|
65
|
+
If you want the result of processing to be multiple files, use the `versions`
|
66
|
+
plugin.
|
67
|
+
|
68
|
+
[image_processing]: https://github.com/janko/image_processing
|