shrine 2.19.3 → 3.6.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 +523 -41
- data/LICENSE.txt +1 -1
- data/README.md +83 -979
- data/doc/advantages.md +231 -204
- data/doc/attacher.md +304 -153
- data/doc/carrierwave.md +297 -226
- data/doc/changing_derivatives.md +308 -0
- data/doc/changing_location.md +103 -21
- data/doc/changing_storage.md +110 -0
- data/doc/creating_persistence_plugins.md +132 -0
- data/doc/creating_plugins.md +43 -23
- data/doc/creating_storages.md +19 -5
- data/doc/design.md +147 -97
- data/doc/direct_s3.md +38 -28
- data/doc/external/articles.md +63 -0
- data/doc/external/extensions.md +53 -0
- data/doc/external/misc.md +32 -0
- data/doc/getting_started.md +1156 -0
- data/doc/metadata.md +190 -109
- data/doc/multiple_files.md +93 -30
- data/doc/paperclip.md +384 -262
- data/doc/plugins/activerecord.md +177 -46
- data/doc/plugins/add_metadata.md +139 -38
- data/doc/plugins/atomic_helpers.md +217 -0
- data/doc/plugins/backgrounding.md +156 -98
- data/doc/plugins/cached_attachment_data.md +7 -5
- data/doc/plugins/column.md +121 -0
- data/doc/plugins/data_uri.md +23 -22
- data/doc/plugins/default_storage.md +36 -10
- data/doc/plugins/default_url.md +30 -13
- data/doc/plugins/delete_raw.md +4 -2
- data/doc/plugins/derivation_endpoint.md +186 -101
- data/doc/plugins/derivatives.md +839 -0
- data/doc/plugins/determine_mime_type.md +4 -2
- data/doc/plugins/download_endpoint.md +64 -8
- data/doc/plugins/dynamic_storage.md +5 -3
- data/doc/plugins/entity.md +263 -0
- data/doc/plugins/form_assign.md +55 -0
- data/doc/plugins/included.md +31 -8
- data/doc/plugins/infer_extension.md +21 -10
- data/doc/plugins/instrumentation.md +38 -16
- data/doc/plugins/keep_files.md +16 -17
- data/doc/plugins/metadata_attributes.md +42 -13
- data/doc/plugins/mirroring.md +118 -0
- data/doc/plugins/model.md +210 -0
- data/doc/plugins/module_include.md +4 -2
- data/doc/plugins/multi_cache.md +24 -0
- data/doc/plugins/persistence.md +101 -0
- data/doc/plugins/presign_endpoint.md +9 -4
- data/doc/plugins/pretty_location.md +16 -3
- data/doc/plugins/processing.md +4 -2
- data/doc/plugins/rack_file.md +8 -2
- data/doc/plugins/rack_response.md +6 -2
- data/doc/plugins/recache.md +4 -2
- data/doc/plugins/refresh_metadata.md +49 -9
- data/doc/plugins/remote_url.md +84 -47
- data/doc/plugins/remove_attachment.md +27 -6
- data/doc/plugins/remove_invalid.md +21 -6
- data/doc/plugins/restore_cached_data.md +11 -3
- data/doc/plugins/sequel.md +159 -35
- data/doc/plugins/signature.md +16 -5
- data/doc/plugins/store_dimensions.md +14 -2
- data/doc/plugins/tempfile.md +4 -2
- data/doc/plugins/type_predicates.md +96 -0
- data/doc/plugins/upload_endpoint.md +13 -13
- data/doc/plugins/upload_options.md +6 -4
- data/doc/plugins/{default_url_options.md → url_options.md} +9 -7
- data/doc/plugins/validation.md +97 -0
- data/doc/plugins/validation_helpers.md +16 -13
- data/doc/plugins/versions.md +15 -19
- data/doc/processing.md +438 -221
- data/doc/refile.md +188 -170
- data/doc/release_notes/1.0.0.md +4 -0
- data/doc/release_notes/1.1.0.md +6 -2
- data/doc/release_notes/1.2.0.md +4 -0
- data/doc/release_notes/1.3.0.md +4 -0
- data/doc/release_notes/1.4.0.md +4 -0
- data/doc/release_notes/1.4.1.md +4 -0
- data/doc/release_notes/1.4.2.md +4 -0
- data/doc/release_notes/2.0.0.md +4 -0
- data/doc/release_notes/2.0.1.md +4 -0
- data/doc/release_notes/2.1.0.md +5 -1
- data/doc/release_notes/2.1.1.md +4 -0
- data/doc/release_notes/2.10.0.md +4 -0
- data/doc/release_notes/2.10.1.md +4 -0
- data/doc/release_notes/2.11.0.md +4 -0
- data/doc/release_notes/2.12.0.md +4 -0
- data/doc/release_notes/2.13.0.md +4 -0
- data/doc/release_notes/2.14.0.md +5 -1
- data/doc/release_notes/2.15.0.md +11 -7
- data/doc/release_notes/2.16.0.md +4 -0
- data/doc/release_notes/2.17.0.md +4 -0
- data/doc/release_notes/2.18.0.md +4 -0
- data/doc/release_notes/2.19.0.md +6 -3
- data/doc/release_notes/2.2.0.md +4 -0
- data/doc/release_notes/2.3.0.md +4 -0
- data/doc/release_notes/2.3.1.md +4 -0
- data/doc/release_notes/2.4.0.md +4 -0
- data/doc/release_notes/2.4.1.md +4 -0
- data/doc/release_notes/2.5.0.md +4 -0
- data/doc/release_notes/2.6.0.md +4 -0
- data/doc/release_notes/2.6.1.md +4 -0
- data/doc/release_notes/2.7.0.md +4 -0
- data/doc/release_notes/2.8.0.md +4 -0
- data/doc/release_notes/2.9.0.md +4 -0
- data/doc/release_notes/3.0.0.md +981 -0
- data/doc/release_notes/3.0.1.md +22 -0
- data/doc/release_notes/3.1.0.md +73 -0
- 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/release_notes/3.5.0.md +63 -0
- data/doc/release_notes/3.6.0.md +23 -0
- data/doc/retrieving_uploads.md +5 -2
- data/doc/securing_uploads.md +60 -37
- data/doc/storage/file_system.md +20 -3
- data/doc/storage/memory.md +19 -0
- data/doc/storage/s3.md +122 -78
- data/doc/testing.md +141 -133
- data/doc/upgrading_to_3.md +708 -0
- data/doc/validation.md +54 -90
- data/lib/shrine/attacher.rb +292 -169
- data/lib/shrine/attachment.rb +13 -46
- data/lib/shrine/plugins/_persistence.rb +93 -0
- data/lib/shrine/plugins/activerecord.rb +77 -34
- data/lib/shrine/plugins/add_metadata.rb +25 -17
- data/lib/shrine/plugins/atomic_helpers.rb +119 -0
- data/lib/shrine/plugins/backgrounding.rb +77 -113
- data/lib/shrine/plugins/cached_attachment_data.rb +6 -15
- data/lib/shrine/plugins/column.rb +102 -0
- data/lib/shrine/plugins/data_uri.rb +38 -36
- data/lib/shrine/plugins/default_storage.rb +45 -15
- data/lib/shrine/plugins/default_url.rb +12 -24
- data/lib/shrine/plugins/default_url_options.rb +3 -30
- data/lib/shrine/plugins/delete_raw.rb +10 -16
- data/lib/shrine/plugins/derivation_endpoint.rb +130 -171
- data/lib/shrine/plugins/derivatives.rb +645 -0
- data/lib/shrine/plugins/determine_mime_type.rb +9 -21
- data/lib/shrine/plugins/download_endpoint.rb +118 -133
- data/lib/shrine/plugins/dynamic_storage.rb +5 -11
- data/lib/shrine/plugins/entity.rb +158 -0
- data/lib/shrine/plugins/form_assign.rb +108 -0
- data/lib/shrine/plugins/included.rb +6 -6
- data/lib/shrine/plugins/infer_extension.rb +17 -20
- data/lib/shrine/plugins/instrumentation.rb +59 -43
- data/lib/shrine/plugins/keep_files.rb +3 -15
- data/lib/shrine/plugins/metadata_attributes.rb +28 -19
- data/lib/shrine/plugins/mirroring.rb +142 -0
- data/lib/shrine/plugins/model.rb +160 -0
- data/lib/shrine/plugins/module_include.rb +3 -3
- data/lib/shrine/plugins/multi_cache.rb +27 -0
- data/lib/shrine/plugins/presign_endpoint.rb +27 -28
- data/lib/shrine/plugins/pretty_location.rb +15 -9
- data/lib/shrine/plugins/processing.rb +22 -9
- data/lib/shrine/plugins/rack_file.rb +2 -42
- data/lib/shrine/plugins/rack_response.rb +21 -10
- data/lib/shrine/plugins/recache.rb +6 -5
- data/lib/shrine/plugins/refresh_metadata.rb +13 -11
- data/lib/shrine/plugins/remote_url.rb +49 -49
- data/lib/shrine/plugins/remove_attachment.rb +12 -6
- data/lib/shrine/plugins/remove_invalid.rb +19 -8
- data/lib/shrine/plugins/restore_cached_data.rb +13 -7
- data/lib/shrine/plugins/sequel.rb +86 -36
- data/lib/shrine/plugins/signature.rb +10 -16
- data/lib/shrine/plugins/store_dimensions.rb +35 -40
- data/lib/shrine/plugins/tempfile.rb +1 -3
- data/lib/shrine/plugins/type_predicates.rb +113 -0
- data/lib/shrine/plugins/upload_endpoint.rb +28 -24
- data/lib/shrine/plugins/upload_options.rb +14 -15
- data/lib/shrine/plugins/url_options.rb +31 -0
- data/lib/shrine/plugins/validation.rb +80 -0
- data/lib/shrine/plugins/validation_helpers.rb +35 -58
- data/lib/shrine/plugins/versions.rb +107 -87
- data/lib/shrine/plugins.rb +22 -0
- data/lib/shrine/storage/file_system.rb +46 -64
- data/lib/shrine/storage/linter.rb +42 -7
- data/lib/shrine/storage/memory.rb +49 -0
- data/lib/shrine/storage/s3.rb +173 -160
- data/lib/shrine/uploaded_file.rb +32 -32
- data/lib/shrine/version.rb +3 -3
- data/lib/shrine.rb +87 -150
- data/shrine.gemspec +11 -12
- metadata +92 -82
- data/doc/migrating_storage.md +0 -76
- data/doc/plugins/backup.md +0 -31
- data/doc/plugins/copy.md +0 -24
- data/doc/plugins/delete_promoted.md +0 -12
- data/doc/plugins/direct_upload.md +0 -172
- data/doc/plugins/hooks.md +0 -58
- data/doc/plugins/logging.md +0 -42
- data/doc/plugins/migration_helpers.md +0 -60
- data/doc/plugins/moving.md +0 -19
- data/doc/plugins/multi_delete.md +0 -20
- data/doc/plugins/parallelize.md +0 -16
- data/doc/plugins/parsed_json.md +0 -23
- data/doc/regenerating_versions.md +0 -143
- data/lib/shrine/plugins/background_helpers.rb +0 -5
- data/lib/shrine/plugins/backup.rb +0 -90
- data/lib/shrine/plugins/copy.rb +0 -50
- data/lib/shrine/plugins/delete_promoted.rb +0 -20
- data/lib/shrine/plugins/direct_upload.rb +0 -217
- data/lib/shrine/plugins/hooks.rb +0 -90
- data/lib/shrine/plugins/logging.rb +0 -142
- data/lib/shrine/plugins/migration_helpers.rb +0 -70
- data/lib/shrine/plugins/moving.rb +0 -57
- data/lib/shrine/plugins/multi_delete.rb +0 -32
- data/lib/shrine/plugins/parallelize.rb +0 -78
- data/lib/shrine/plugins/parsed_json.rb +0 -29
|
@@ -1,172 +0,0 @@
|
|
|
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`][direct_upload] plugin provides a Rack endpoint which can
|
|
7
|
-
be used for uploading individual files asynchronously. It requires the [Roda]
|
|
8
|
-
gem.
|
|
9
|
-
|
|
10
|
-
```rb
|
|
11
|
-
plugin :direct_upload
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
The Roda endpoint provides two routes:
|
|
15
|
-
|
|
16
|
-
* `POST /:storage/upload`
|
|
17
|
-
* `GET /:storage/presign`
|
|
18
|
-
|
|
19
|
-
This first route is for doing direct uploads to your app, the received file
|
|
20
|
-
will be uploaded the underlying storage. The second route is for doing direct
|
|
21
|
-
uploads to a 3rd-party service, it will return the URL where the file can be
|
|
22
|
-
uploaded to, along with the necessary request parameters.
|
|
23
|
-
|
|
24
|
-
This is how you can mount the endpoint in a Rails application:
|
|
25
|
-
|
|
26
|
-
```rb
|
|
27
|
-
Rails.application.routes.draw do
|
|
28
|
-
mount ImageUploader::UploadEndpoint => "/images"
|
|
29
|
-
end
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
Now your application will get `POST /images/cache/upload` and `GET
|
|
33
|
-
/images/cache/presign` routes. On the client side it is recommended to use
|
|
34
|
-
[Uppy] for uploading files to the app or directly to the 3rd-party service.
|
|
35
|
-
|
|
36
|
-
## Uploads
|
|
37
|
-
|
|
38
|
-
The upload route accepts a "file" query parameter, and returns the uploaded
|
|
39
|
-
file in JSON format:
|
|
40
|
-
|
|
41
|
-
```rb
|
|
42
|
-
# POST /images/cache/upload
|
|
43
|
-
{
|
|
44
|
-
"id": "43kewit94.jpg",
|
|
45
|
-
"storage": "cache",
|
|
46
|
-
"metadata": {
|
|
47
|
-
"size": 384393,
|
|
48
|
-
"filename": "nature.jpg",
|
|
49
|
-
"mime_type": "image/jpeg"
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
Once you've uploaded the file, you can assign the result to the hidden
|
|
55
|
-
attachment field in the form, or immediately send it to the server.
|
|
56
|
-
|
|
57
|
-
Note that the endpoint uploads the file standalone, without any knowledge of
|
|
58
|
-
the record, so `context[:record]` and `context[:name]` will be nil.
|
|
59
|
-
|
|
60
|
-
### Limiting filesize
|
|
61
|
-
|
|
62
|
-
It's good idea to limit the maximum filesize of uploaded files, if you set the
|
|
63
|
-
`:max_size` option, files which are too big will get automatically deleted and
|
|
64
|
-
413 status will be returned:
|
|
65
|
-
|
|
66
|
-
```rb
|
|
67
|
-
plugin :direct_upload, max_size: 5*1024*1024 # 5 MB
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
Note that this option doesn't affect presigned uploads, there you can apply
|
|
71
|
-
filesize limit when generating a presign. The filesize constraint here is for
|
|
72
|
-
security purposes, you should still perform file validations on attaching.
|
|
73
|
-
|
|
74
|
-
## Presigns
|
|
75
|
-
|
|
76
|
-
The presign route returns the URL to the 3rd-party service to which you can
|
|
77
|
-
upload the file, along with the necessary query parameters.
|
|
78
|
-
|
|
79
|
-
```rb
|
|
80
|
-
# GET /images/cache/presign
|
|
81
|
-
{
|
|
82
|
-
"url" => "https://my-bucket.s3-eu-west-1.amazonaws.com",
|
|
83
|
-
"fields" => {
|
|
84
|
-
"key" => "b7d575850ba61b44c8a9ff889dfdb14d88cdc25f8dd121004c8",
|
|
85
|
-
"policy" => "eyJleHBpcmF0aW9uIjoiMjAxNS0QwMToxMToyOVoiLCJjb2...",
|
|
86
|
-
"x-amz-credential" => "AKIAIJF55TMZYT6Q/20151024/eu-west-1/s3/aws4_request",
|
|
87
|
-
"x-amz-algorithm" => "AWS4-HMAC-SHA256",
|
|
88
|
-
"x-amz-date" => "20151024T001129Z",
|
|
89
|
-
"x-amz-signature" => "c1eb634f83f96b69bd675f535b3ff15ae184b102fcba51e4db5f4959b4ae26f4"
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
If you want that the generated location includes a file extension, you can
|
|
95
|
-
specify the `extension` query parameter: `GET
|
|
96
|
-
/:storage/presign?extension=.png`.
|
|
97
|
-
|
|
98
|
-
You can also completely change how the key is generated, with
|
|
99
|
-
`:presign_location`:
|
|
100
|
-
|
|
101
|
-
```rb
|
|
102
|
-
plugin :direct_upload, presign_location: -> (request) { "${filename}" }
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
This presign route internally calls `#presign` on the storage, and many
|
|
106
|
-
storages accept additional service-specific options. You can generate these
|
|
107
|
-
additional options per-request through `:presign_options`:
|
|
108
|
-
|
|
109
|
-
```rb
|
|
110
|
-
plugin :direct_upload, presign_options: { acl: "public-read" }
|
|
111
|
-
|
|
112
|
-
plugin :direct_upload, presign_options: ->(request) do
|
|
113
|
-
filename = request.params["filename"]
|
|
114
|
-
content_type = Rack::Mime.mime_type(File.extname(filename))
|
|
115
|
-
|
|
116
|
-
{
|
|
117
|
-
content_length_range: 0..(10*1024*1024), # limit filesize to 10MB
|
|
118
|
-
content_disposition: "attachment; filename=\"#{filename}\"", # download with original filename
|
|
119
|
-
content_type: content_type, # set correct content type
|
|
120
|
-
}
|
|
121
|
-
end
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
Both `:presign_location` and `:presign_options` in their block versions are
|
|
125
|
-
yielded an instance of [Roda request], which is a subclass of `Rack::Request`.
|
|
126
|
-
|
|
127
|
-
See the [Direct Uploads to S3] guide for further instructions on how to hook
|
|
128
|
-
the presigned uploads to a form.
|
|
129
|
-
|
|
130
|
-
## Allowed storages
|
|
131
|
-
|
|
132
|
-
By default only uploads to `:cache` are allowed, to prevent the possibility of
|
|
133
|
-
having orphan files in your main storage. But you can allow more storages:
|
|
134
|
-
|
|
135
|
-
```rb
|
|
136
|
-
plugin :direct_upload, allowed_storages: [:cache, :store]
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
## Customizing endpoint
|
|
140
|
-
|
|
141
|
-
Since the endpoint is a [Roda] app, it is very customizable. For example, you
|
|
142
|
-
can add a Rack middleware to change the response status and headers:
|
|
143
|
-
|
|
144
|
-
```rb
|
|
145
|
-
class ShrineUploadMiddleware
|
|
146
|
-
def initialize(app)
|
|
147
|
-
@app = app
|
|
148
|
-
end
|
|
149
|
-
|
|
150
|
-
def call(env)
|
|
151
|
-
result = @app.call(env)
|
|
152
|
-
|
|
153
|
-
if result[0] == 200 && env["PATH_INFO"].end_with?("upload")
|
|
154
|
-
result[0] = 201
|
|
155
|
-
result[1]["Location"] = Shrine.uploaded_file(result[2].first).url
|
|
156
|
-
end
|
|
157
|
-
|
|
158
|
-
result
|
|
159
|
-
end
|
|
160
|
-
end
|
|
161
|
-
|
|
162
|
-
Shrine::UploadEndpoint.use ShrineUploadMiddleware
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
Upon subclassing uploader the upload endpoint is also subclassed. You can also
|
|
166
|
-
call the plugin again in an uploader subclass to change its configuration.
|
|
167
|
-
|
|
168
|
-
[direct_upload]: /lib/shrine/plugins/direct_upload.rb
|
|
169
|
-
[Roda]: https://github.com/jeremyevans/roda
|
|
170
|
-
[Uppy]: https://uppy.io
|
|
171
|
-
[Roda request]: http://roda.jeremyevans.net/rdoc/classes/Roda/RodaPlugins/Base/RequestMethods.html
|
|
172
|
-
[Direct Uploads to S3]: /doc/direct_s3.md#readme
|
data/doc/plugins/hooks.md
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
# Hooks
|
|
2
|
-
|
|
3
|
-
The [`hooks`][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
|
-
```
|
|
57
|
-
|
|
58
|
-
[hooks]: /lib/shrine/plugins/hooks.rb
|
data/doc/plugins/logging.md
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
# Logging
|
|
2
|
-
|
|
3
|
-
The [`logging`][logging] plugin logs any storing/processing/deleting that is
|
|
4
|
-
performed.
|
|
5
|
-
|
|
6
|
-
```rb
|
|
7
|
-
plugin :logging
|
|
8
|
-
```
|
|
9
|
-
|
|
10
|
-
This plugin is useful when you want to have overview of what exactly is going
|
|
11
|
-
on, or you simply want to have it logged for future debugging. By default the
|
|
12
|
-
logging output looks something like this:
|
|
13
|
-
|
|
14
|
-
```
|
|
15
|
-
2015-10-09T20:06:06.676Z #25602: STORE[cache] ImageUploader[:avatar] User[29543] 1 file (0.1s)
|
|
16
|
-
2015-10-09T20:06:06.854Z #25602: PROCESS[store]: ImageUploader[:avatar] User[29543] 1-3 files (0.22s)
|
|
17
|
-
2015-10-09T20:06:07.133Z #25602: DELETE[destroyed]: ImageUploader[:avatar] User[29543] 3 files (0.07s)
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
The plugin accepts the following options:
|
|
21
|
-
|
|
22
|
-
| Option | Description |
|
|
23
|
-
| :-------- | :---------- |
|
|
24
|
-
| `:format` | This allows you to change the logging output into something that may be easier to grep. Accepts `:human` (default), `:json` and `:logfmt`. |
|
|
25
|
-
| `: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). |
|
|
26
|
-
| `: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`. |
|
|
27
|
-
|
|
28
|
-
The default format is probably easiest to read, but may not be easiest to grep.
|
|
29
|
-
If this is important to you, you can switch to another format:
|
|
30
|
-
|
|
31
|
-
```rb
|
|
32
|
-
plugin :logging, format: :json
|
|
33
|
-
# {"action":"upload","phase":"cache","uploader":"ImageUploader","attachment":"avatar",...}
|
|
34
|
-
|
|
35
|
-
plugin :logging, format: :logfmt
|
|
36
|
-
# action=upload phase=cache uploader=ImageUploader attachment=avatar record_class=User ...
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
Logging is by default disabled in tests, but you can enable it by setting
|
|
40
|
-
`Shrine.logger.level = Logger::INFO`.
|
|
41
|
-
|
|
42
|
-
[logging]: /lib/shrine/plugins/logging.rb
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
# Migration Helpers
|
|
2
|
-
|
|
3
|
-
The [`migration_helpers`][migration_helpers] plugin gives the attacher
|
|
4
|
-
additional helper methods which 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
|
-
```
|
|
59
|
-
|
|
60
|
-
[migration_helpers]: /lib/shrine/plugins/migration_helpers.rb
|
data/doc/plugins/moving.md
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
# Moving
|
|
2
|
-
|
|
3
|
-
The [`moving`][moving] plugin will *move* files to storages instead of copying
|
|
4
|
-
them, when the storage supports it. For FileSystem this will issue a `mv`
|
|
5
|
-
command, which is instantaneous regardless of the filesize, so in that case
|
|
6
|
-
loading this 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
|
-
```
|
|
18
|
-
|
|
19
|
-
[moving]: /lib/shrine/plugins/moving.rb
|
data/doc/plugins/multi_delete.md
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
# Multi Delete
|
|
2
|
-
|
|
3
|
-
The [`multi_delete`][multi_delete] plugins allows you to leverage your
|
|
4
|
-
storage's multi delete 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.
|
|
19
|
-
|
|
20
|
-
[multi_delete]: /lib/shrine/plugins/multi_delete.rb
|
data/doc/plugins/parallelize.md
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
# Parallelize
|
|
2
|
-
|
|
3
|
-
The [`parallelize`][parallelize] plugin parallelizes uploads and deletes of
|
|
4
|
-
multiple versions 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
|
-
```
|
|
15
|
-
|
|
16
|
-
[parallelize]: /lib/shrine/plugins/parallelize.rb
|
data/doc/plugins/parsed_json.md
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
# Parsed JSON
|
|
2
|
-
|
|
3
|
-
The [`parsed_json`][parsed_json] plugin is suitable for the case when your
|
|
4
|
-
framework is automatically parsing JSON query parameters, allowing you to
|
|
5
|
-
assign cached files with hashes/arrays.
|
|
6
|
-
|
|
7
|
-
```rb
|
|
8
|
-
plugin :parsed_json
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
```rb
|
|
12
|
-
photo.image = {
|
|
13
|
-
"id" => "sdf90s2443.jpg",
|
|
14
|
-
"storage" => "cache",
|
|
15
|
-
"metadata" => {
|
|
16
|
-
"filename" => "nature.jpg",
|
|
17
|
-
"size" => 29475,
|
|
18
|
-
"mime_type" => "image/jpeg",
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
[parsed_json]: /lib/shrine/plugins/parsed_json.rb
|
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
# Reprocessing Versions
|
|
2
|
-
|
|
3
|
-
While your app is serving uploads in production, you may realize that you want
|
|
4
|
-
to change how your attachment's versions are generated. This means that, in
|
|
5
|
-
addition to changing your processing code, you also need to reprocess the
|
|
6
|
-
existing attachments. This guide is aimed to help doing this migration with
|
|
7
|
-
zero downtime and no unused files left in the main storage.
|
|
8
|
-
|
|
9
|
-
## Adding versions
|
|
10
|
-
|
|
11
|
-
Most common scenario is when initially you're not doing any processing, but
|
|
12
|
-
later decide that you want to generate versions. First you need to update your
|
|
13
|
-
code to generate versions, and you also need to change your views to use those
|
|
14
|
-
versions:
|
|
15
|
-
|
|
16
|
-
```rb
|
|
17
|
-
class ImageUploader < Shrine
|
|
18
|
-
# ...
|
|
19
|
-
|
|
20
|
-
process(:store) do |io, context|
|
|
21
|
-
thumbnail = process_thumbnail(io.download)
|
|
22
|
-
{original: io, thumbnail: thumbnail}
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
```
|
|
26
|
-
```rb
|
|
27
|
-
# In your views add the version name to all <attachment>_url calls.
|
|
28
|
-
user.avatar_url(:thumb)
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
Note that you should deploy both of these changes at once, because the
|
|
32
|
-
`<attachment>_url` method will fail if there are versions generated but no
|
|
33
|
-
version name was passed in. If a version name was passed in but versions aren't
|
|
34
|
-
generated yet (which will be the case here), it will just return the
|
|
35
|
-
unprocessed file URL.
|
|
36
|
-
|
|
37
|
-
Afterwards you should run a script which reprocesses the versions for existing
|
|
38
|
-
files:
|
|
39
|
-
|
|
40
|
-
```rb
|
|
41
|
-
User.paged_each do |user|
|
|
42
|
-
attacher, attachment = user.avatar_attacher, user.avatar
|
|
43
|
-
if attacher.stored? && !attachment.is_a?(Hash)
|
|
44
|
-
file = some_processing(attachment.download)
|
|
45
|
-
thumb = attacher.store!(file, version: :thumb)
|
|
46
|
-
attacher.swap({original: attachment, thumb: thumb})
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
## Reprocessing a single version
|
|
52
|
-
|
|
53
|
-
The simplest scenario is where you need to regenerate an existing version.
|
|
54
|
-
First you need to change and deploy your updated processing code, and
|
|
55
|
-
afterwards you can run a script like this on your production database:
|
|
56
|
-
|
|
57
|
-
```rb
|
|
58
|
-
User.paged_each do |user|
|
|
59
|
-
attacher, attachment = user.avatar_attacher, user.avatar
|
|
60
|
-
if attacher.stored?
|
|
61
|
-
file = some_processing(attachment[:original].download)
|
|
62
|
-
thumb = attachment[:thumb].replace(thumb)
|
|
63
|
-
attacher.swap(attachment.merge(thumb: thumb))
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
### Adding a new version
|
|
69
|
-
|
|
70
|
-
When adding a new version to a production app, first add it to the list and
|
|
71
|
-
update your processing code to generate it, and deploy it:
|
|
72
|
-
|
|
73
|
-
```rb
|
|
74
|
-
class ImageUploader < Shrine
|
|
75
|
-
# ...
|
|
76
|
-
|
|
77
|
-
process(:store) do |io, context|
|
|
78
|
-
# ...
|
|
79
|
-
new = some_processing(io.download, *args)
|
|
80
|
-
{small: small, medium: medium, new: new} # we generate the ":new" version
|
|
81
|
-
end
|
|
82
|
-
end
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
After you've deployed this change, you should run a script that will generate
|
|
86
|
-
the new version for all existing records:
|
|
87
|
-
|
|
88
|
-
```rb
|
|
89
|
-
User.paged_each do |user|
|
|
90
|
-
attacher, attachment = user.avatar_attacher, user.avatar
|
|
91
|
-
if attacher.stored? && !attachment[:new]
|
|
92
|
-
file = some_processing(attachment[:original].download, *args)
|
|
93
|
-
new = attacher.store!(file, version: :new)
|
|
94
|
-
attacher.swap(attachment.merge(new: new))
|
|
95
|
-
end
|
|
96
|
-
end
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
After you've run this script on your production database, all records should
|
|
100
|
-
have the new version, and now you should be able to safely update your app to
|
|
101
|
-
use it.
|
|
102
|
-
|
|
103
|
-
### Removing a version
|
|
104
|
-
|
|
105
|
-
Before removing a version, you first need to update your processing to not
|
|
106
|
-
generate it (but keep the version name in the list), as well as update your app
|
|
107
|
-
not to use the new version, and deploy that code. After you've done that, you
|
|
108
|
-
can run a script which removes that version:
|
|
109
|
-
|
|
110
|
-
```rb
|
|
111
|
-
old_versions = []
|
|
112
|
-
|
|
113
|
-
User.paged_each do |user|
|
|
114
|
-
attacher, attachment = user.avatar_attacher, user.avatar
|
|
115
|
-
if attacher.stored? && attachment[:old_version]
|
|
116
|
-
old_versions << attachment.delete(:old_version)
|
|
117
|
-
attacher.swap(attachment)
|
|
118
|
-
end
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
if old_versions.any?
|
|
122
|
-
uploader = old_versions.first.uploader
|
|
123
|
-
uploader.delete(old_versions)
|
|
124
|
-
end
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
After the script has finished, you should be able to safely remove the version
|
|
128
|
-
name from the list.
|
|
129
|
-
|
|
130
|
-
## Reprocessing all versions
|
|
131
|
-
|
|
132
|
-
If you made a lot of changes to versions, it might make sense to simply
|
|
133
|
-
regenerate all versions. After you've deployed the change in processing, you
|
|
134
|
-
can run a script which updates existing records:
|
|
135
|
-
|
|
136
|
-
```rb
|
|
137
|
-
User.paged_each do |user|
|
|
138
|
-
if user.avatar_attacher.stored?
|
|
139
|
-
# assuming your largest version is named ":original"
|
|
140
|
-
user.update(avatar: user.avatar[:original])
|
|
141
|
-
end
|
|
142
|
-
end
|
|
143
|
-
```
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
Shrine.deprecation("The background_helpers plugin has been renamed to \"backgrounding\". Loading the plugin through \"background_helpers\" will stop working in Shrine 3.")
|
|
4
|
-
require "shrine/plugins/backgrounding"
|
|
5
|
-
Shrine::Plugins.register_plugin(:background_helpers, Shrine::Plugins::Backgrounding)
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
Shrine.deprecation("The backup plugin has been deprecated, the new preferred way to implement mirroring is via the instrumentation plugin – see https://github.com/shrinerb/shrine/wiki/Mirroring-Uploads. The backup plugin will be removed in Shrine 3.")
|
|
4
|
-
|
|
5
|
-
class Shrine
|
|
6
|
-
module Plugins
|
|
7
|
-
# Documentation lives in [doc/plugins/backup.md] on GitHub.
|
|
8
|
-
#
|
|
9
|
-
# [doc/plugins/backup.md]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/backup.md
|
|
10
|
-
module Backup
|
|
11
|
-
def self.configure(uploader, opts = {})
|
|
12
|
-
uploader.opts[:backup_storage] = opts.fetch(:storage, uploader.opts[:backup_storage])
|
|
13
|
-
uploader.opts[:backup_delete] = opts.fetch(:delete, uploader.opts.fetch(:backup_delete, true))
|
|
14
|
-
|
|
15
|
-
raise Error, "The :storage option is required for backup plugin" if uploader.opts[:backup_storage].nil?
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
module AttacherMethods
|
|
19
|
-
# Backs up the stored file after promoting.
|
|
20
|
-
def promote(*)
|
|
21
|
-
result = super
|
|
22
|
-
store_backup!(result) if result
|
|
23
|
-
result
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
# Deletes the backup file in addition to the stored file.
|
|
27
|
-
def replace
|
|
28
|
-
result = super
|
|
29
|
-
delete_backup!(@old) if result && delete_backup?
|
|
30
|
-
result
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
# Deletes the backup file in addition to the stored file.
|
|
34
|
-
def destroy
|
|
35
|
-
result = super
|
|
36
|
-
delete_backup!(get) if result && delete_backup?
|
|
37
|
-
result
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
# Returns a copy of the given uploaded file with storage changed to
|
|
41
|
-
# backup storage.
|
|
42
|
-
def backup_file(uploaded_file)
|
|
43
|
-
uploaded_file(uploaded_file.to_json) do |file|
|
|
44
|
-
file.data["storage"] = backup_storage.to_s
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
private
|
|
49
|
-
|
|
50
|
-
# Upload the stored file to the backup storage.
|
|
51
|
-
def store_backup!(stored_file)
|
|
52
|
-
options = _equalize_phase_and_action(action: :backup, move: false)
|
|
53
|
-
backup_store.upload(stored_file, context.merge(options))
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
# Deleted the stored file from the backup storage.
|
|
57
|
-
def delete_backup!(deleted_file)
|
|
58
|
-
_delete(backup_file(deleted_file), action: :backup)
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
def backup_store
|
|
62
|
-
@backup_store ||= shrine_class.new(backup_storage)
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
def backup_storage
|
|
66
|
-
shrine_class.opts[:backup_storage]
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
def delete_backup?
|
|
70
|
-
shrine_class.opts[:backup_delete]
|
|
71
|
-
end
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
module InstanceMethods
|
|
75
|
-
private
|
|
76
|
-
|
|
77
|
-
# We preserve the location when uploading from store to backup.
|
|
78
|
-
def get_location(io, context)
|
|
79
|
-
if context[:action] == :backup
|
|
80
|
-
io.id
|
|
81
|
-
else
|
|
82
|
-
super
|
|
83
|
-
end
|
|
84
|
-
end
|
|
85
|
-
end
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
register_plugin(:backup, Backup)
|
|
89
|
-
end
|
|
90
|
-
end
|