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
data/doc/carrierwave.md
CHANGED
|
@@ -1,16 +1,52 @@
|
|
|
1
|
-
|
|
1
|
+
---
|
|
2
|
+
title: Upgrading from CarrierWave
|
|
3
|
+
---
|
|
2
4
|
|
|
3
5
|
This guide is aimed at helping CarrierWave users transition to Shrine, and it
|
|
4
6
|
consists of three parts:
|
|
5
7
|
|
|
6
8
|
1. Explanation of the key differences in design between CarrierWave and Shrine
|
|
7
|
-
2. Instructions how to migrate
|
|
9
|
+
2. Instructions how to migrate an existing app that uses CarrierWave to Shrine
|
|
8
10
|
3. Extensive reference of CarrierWave's interface with Shrine equivalents
|
|
9
11
|
|
|
10
|
-
##
|
|
12
|
+
## Overview
|
|
11
13
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
+
### Uploader
|
|
15
|
+
|
|
16
|
+
Shrine shares CarrierWave's concept of **uploaders**, classes which encapsulate
|
|
17
|
+
file attachment logic for different file types:
|
|
18
|
+
|
|
19
|
+
```rb
|
|
20
|
+
class ImageUploader < Shrine
|
|
21
|
+
# attachment logic
|
|
22
|
+
end
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
However, while CarrierWave uploaders are responsible for most of the
|
|
26
|
+
attachment logic (uploading to temporary/permanent storage, retrieving the
|
|
27
|
+
uploaded file, file validation, processing versions), Shrine distributes
|
|
28
|
+
these responsibilities across several core classes:
|
|
29
|
+
|
|
30
|
+
| Class | Description |
|
|
31
|
+
| :---- | :----------- |
|
|
32
|
+
| `Shrine` | handles uploads, metadata extraction, location generation |
|
|
33
|
+
| `Shrine::UploadedFile` | exposes metadata, implements downloading, URL generation, deletion |
|
|
34
|
+
| `Shrine::Attacher` | handles caching & storing, dirty tracking, persistence, versions |
|
|
35
|
+
|
|
36
|
+
Shrine uploaders themselves are functional: they receive a file on the input
|
|
37
|
+
and return the uploaded file on the output. There are no state changes.
|
|
38
|
+
|
|
39
|
+
```rb
|
|
40
|
+
uploader = ImageUploader.new(:store)
|
|
41
|
+
uploaded_file = uploader.upload(file, :store)
|
|
42
|
+
uploaded_file #=> #<Shrine::UploadedFile>
|
|
43
|
+
uploaded_file.url #=> "https://my-bucket.s3.amazonaws.com/store/kfds0lg9rer.jpg"
|
|
44
|
+
uploaded_file.download #=> #<File:/tmp/path/to/file>
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Storage
|
|
48
|
+
|
|
49
|
+
In CarrierWave, you configure storage in global configuration:
|
|
14
50
|
|
|
15
51
|
```rb
|
|
16
52
|
CarrierWave.configure do |config|
|
|
@@ -24,6 +60,9 @@ CarrierWave.configure do |config|
|
|
|
24
60
|
config.fog_directory = "my-bucket"
|
|
25
61
|
end
|
|
26
62
|
```
|
|
63
|
+
|
|
64
|
+
In Shrine, the configuration options are passed directly to the storage class:
|
|
65
|
+
|
|
27
66
|
```rb
|
|
28
67
|
Shrine.storages[:store] = Shrine::Storage::S3.new(
|
|
29
68
|
bucket: "my-bucket",
|
|
@@ -33,11 +72,11 @@ Shrine.storages[:store] = Shrine::Storage::S3.new(
|
|
|
33
72
|
)
|
|
34
73
|
```
|
|
35
74
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
temporary
|
|
39
|
-
|
|
40
|
-
|
|
75
|
+
#### Temporary storage
|
|
76
|
+
|
|
77
|
+
Where CarrierWave's temporary storage is hardcoded to disk, Shrine can use any
|
|
78
|
+
storage for temporary storage. So, if you have multiple servers or want to do
|
|
79
|
+
[direct uploads], you can use AWS S3 as temporary storage:
|
|
41
80
|
|
|
42
81
|
```rb
|
|
43
82
|
Shrine.storages = {
|
|
@@ -46,97 +85,131 @@ Shrine.storages = {
|
|
|
46
85
|
}
|
|
47
86
|
```
|
|
48
87
|
|
|
49
|
-
|
|
88
|
+
### Persistence
|
|
50
89
|
|
|
51
|
-
|
|
52
|
-
|
|
90
|
+
While CarrierWave persists only the filename of the original uploaded file,
|
|
91
|
+
Shrine persists storage and metadata information as well:
|
|
53
92
|
|
|
54
93
|
```rb
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
94
|
+
{
|
|
95
|
+
"id": "path/to/image.jpg",
|
|
96
|
+
"storage": "store",
|
|
97
|
+
"metadata": {
|
|
98
|
+
"filename": "nature.jpg",
|
|
99
|
+
"size": 4739472,
|
|
100
|
+
"mime_type": "image/jpeg"
|
|
101
|
+
}
|
|
102
|
+
}
|
|
58
103
|
```
|
|
59
104
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
`Shrine::UploadedFile` class which represents the uploaded file.
|
|
105
|
+
This way we have all information about uploaded files, without having to
|
|
106
|
+
retrieve the file from the storage.
|
|
63
107
|
|
|
64
108
|
```rb
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
109
|
+
photo.image.id #=> "path/to/image.jpg"
|
|
110
|
+
photo.image.storage_key #=> :store
|
|
111
|
+
photo.image.metadata #=> { "filename" => "...", "size" => ..., "mime_type" => "..." }
|
|
112
|
+
|
|
113
|
+
photo.image.original_filename #=> "nature.jpg"
|
|
114
|
+
photo.image.size #=> 4739472
|
|
115
|
+
photo.image.mime_type #=> "image/jpeg"
|
|
69
116
|
```
|
|
70
117
|
|
|
118
|
+
#### Location
|
|
119
|
+
|
|
120
|
+
CarrierWave persists only the filename of the uploaded file, and recalculates
|
|
121
|
+
the full location dynamically based on location configuration. This can be
|
|
122
|
+
dangerous, because if some component of the location happens to change, all
|
|
123
|
+
existing links might become invalid.
|
|
124
|
+
|
|
125
|
+
To avoid this, Shrine persists the full location on attachment, and uses it
|
|
126
|
+
when generating file URL. So, even if you change how file locations are
|
|
127
|
+
generated, existing files that are on old locations will still remain
|
|
128
|
+
accessible.
|
|
129
|
+
|
|
71
130
|
### Processing
|
|
72
131
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
file or a hash of versions:
|
|
132
|
+
CarrierWave uses a class-level DSL for generating versions, which internally
|
|
133
|
+
uses uploader subclassing and does in-place processing.
|
|
76
134
|
|
|
77
135
|
```rb
|
|
78
136
|
class ImageUploader < CarrierWave::Uploader::Base
|
|
79
137
|
include CarrierWave::MiniMagick
|
|
80
138
|
|
|
81
|
-
|
|
139
|
+
version :large do
|
|
140
|
+
process resize_to_limit: [800, 800]
|
|
141
|
+
end
|
|
82
142
|
|
|
83
143
|
version :medium do
|
|
84
144
|
process resize_to_limit: [500, 500]
|
|
85
145
|
end
|
|
86
146
|
|
|
87
|
-
version :small
|
|
147
|
+
version :small do
|
|
88
148
|
process resize_to_limit: [300, 300]
|
|
89
149
|
end
|
|
90
150
|
end
|
|
91
151
|
```
|
|
92
152
|
|
|
153
|
+
In contrast, in Shrine you perform processing on the instance level as a
|
|
154
|
+
functional transformation, which is a lot simpler and more flexible:
|
|
155
|
+
|
|
93
156
|
```rb
|
|
94
157
|
require "image_processing/mini_magick"
|
|
95
158
|
|
|
96
159
|
class ImageUploader < Shrine
|
|
97
|
-
plugin :
|
|
98
|
-
plugin :versions
|
|
99
|
-
|
|
100
|
-
process(:store) do |io, context|
|
|
101
|
-
versions = {}
|
|
160
|
+
plugin :derivatives
|
|
102
161
|
|
|
103
|
-
|
|
104
|
-
|
|
162
|
+
Attacher.derivatives do |original|
|
|
163
|
+
magick = ImageProcessing::MiniMagick.source(original)
|
|
105
164
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
versions # return the hash of processed files
|
|
165
|
+
{
|
|
166
|
+
large: magick.resize_to_limit!(800, 800),
|
|
167
|
+
medium: magick.resize_to_limit!(500, 500),
|
|
168
|
+
small: magick.resize_to_limit!(300, 300),
|
|
169
|
+
}
|
|
112
170
|
end
|
|
113
171
|
end
|
|
114
172
|
```
|
|
115
173
|
|
|
116
|
-
|
|
117
|
-
which files are processed from which, and even add parallelization.
|
|
174
|
+
#### Retrieving versions
|
|
118
175
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
176
|
+
When retrieving versions, CarrierWave returns a list of declared versions which
|
|
177
|
+
may or may not have been generated. In contrast, Shrine persists data of
|
|
178
|
+
uploaded processed files into the database (including any extracted metadata),
|
|
179
|
+
which then becomes the source of truth on which versions have been generated.
|
|
180
|
+
|
|
181
|
+
```rb
|
|
182
|
+
photo.image #=> #<Shrine::UploadedFile id="original.jpg" ...>
|
|
183
|
+
photo.image_derivatives #=> {}
|
|
184
|
+
|
|
185
|
+
photo.image_derivatives! # triggers processing
|
|
186
|
+
photo.image_derivatives #=>
|
|
187
|
+
# {
|
|
188
|
+
# large: #<Shrine::UploadedFile id="large.jpg" metadata={"size"=>873232, ...} ...>,
|
|
189
|
+
# medium: #<Shrine::UploadedFile id="medium.jpg" metadata={"size"=>94823, ...} ...>,
|
|
190
|
+
# small: #<Shrine::UploadedFile id="small.jpg" metadata={"size"=>37322, ...} ...>,
|
|
191
|
+
# }
|
|
192
|
+
```
|
|
122
193
|
|
|
123
194
|
#### Reprocessing versions
|
|
124
195
|
|
|
125
196
|
Shrine doesn't have a built-in way of regenerating versions, because that has
|
|
126
|
-
to be written and optimized differently depending on
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
197
|
+
to be written and optimized differently depending on what versions have changed
|
|
198
|
+
which persistence library you're using, how many records there are in the table
|
|
199
|
+
etc.
|
|
200
|
+
|
|
201
|
+
However, there is an extensive guide for [Managing Derivatives], which provides
|
|
202
|
+
instructions on how to make these changes safely and with zero downtime.
|
|
130
203
|
|
|
131
|
-
###
|
|
204
|
+
### Validation
|
|
132
205
|
|
|
133
|
-
|
|
134
|
-
|
|
206
|
+
File validation in Shrine is also instance-level, which allows using
|
|
207
|
+
conditionals:
|
|
135
208
|
|
|
136
209
|
```rb
|
|
137
210
|
class ImageUploader < CarrierWave::Uploader::Base
|
|
138
211
|
def extension_whitelist
|
|
139
|
-
%w[jpg jpeg
|
|
212
|
+
%w[jpg jpeg png webp]
|
|
140
213
|
end
|
|
141
214
|
|
|
142
215
|
def content_type_whitelist
|
|
@@ -154,107 +227,75 @@ class ImageUploader < Shrine
|
|
|
154
227
|
plugin :validation_helpers
|
|
155
228
|
|
|
156
229
|
Attacher.validate do
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
230
|
+
validate_max_size 10*1024*1024
|
|
231
|
+
validate_extension %w[jpg jpeg png webp]
|
|
232
|
+
|
|
233
|
+
if validate_mime_type %w[image/jpeg image/png image/webp]
|
|
234
|
+
validate_max_dimensions [5000, 5000]
|
|
235
|
+
end
|
|
160
236
|
end
|
|
161
237
|
end
|
|
162
238
|
```
|
|
163
239
|
|
|
164
|
-
|
|
240
|
+
#### Custom metadata
|
|
165
241
|
|
|
166
|
-
|
|
167
|
-
plugins for both Sequel and ActiveRecord, but can also be used with just PORO
|
|
168
|
-
models.
|
|
242
|
+
With Shrine you can also extract and validate any custom metadata:
|
|
169
243
|
|
|
170
244
|
```rb
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
245
|
+
class VideoUploader < Shrine
|
|
246
|
+
plugin :add_metadata
|
|
247
|
+
plugin :validation
|
|
174
248
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
249
|
+
add_metadata :duration do |io|
|
|
250
|
+
FFMPEG::Movie.new(io.path).duration
|
|
251
|
+
end
|
|
178
252
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
end
|
|
184
|
-
```
|
|
185
|
-
```rb
|
|
186
|
-
class Photo < ActiveRecord::Base
|
|
187
|
-
include ImageUploader::Attachment.new(:avatar)
|
|
253
|
+
Attacher.validate do
|
|
254
|
+
if file.duration > 5*60*60
|
|
255
|
+
errors << "must not be longer than 5 hours"
|
|
256
|
+
end
|
|
257
|
+
end
|
|
188
258
|
end
|
|
189
259
|
```
|
|
190
260
|
|
|
191
|
-
###
|
|
261
|
+
### Multiple uploads
|
|
192
262
|
|
|
193
|
-
|
|
194
|
-
|
|
263
|
+
Shrine doesn't have support for multiple uploads out-of-the-box like
|
|
264
|
+
CarrierWave does. Instead, you can implement them using a separate table with a
|
|
265
|
+
one-to-many relationship to which the files will be attached. The [Multiple
|
|
266
|
+
Files] guide explains this setup in more detail.
|
|
195
267
|
|
|
196
|
-
|
|
197
|
-
photo.image_data #=>
|
|
198
|
-
# {
|
|
199
|
-
# "storage" => "store",
|
|
200
|
-
# "id" => "photo/1/image/0d9o8dk42.png",
|
|
201
|
-
# "metadata" => {
|
|
202
|
-
# "filename" => "nature.png",
|
|
203
|
-
# "size" => 49349138,
|
|
204
|
-
# "mime_type" => "image/png"
|
|
205
|
-
# }
|
|
206
|
-
# }
|
|
268
|
+
## Migrating from CarrierWave
|
|
207
269
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
photo.image.mime_type #=> "image/png"
|
|
211
|
-
```
|
|
270
|
+
You have an existing app using CarrierWave and you want to transfer it to
|
|
271
|
+
Shrine. Let's assume we have a `Photo` model with the "image" attachment.
|
|
212
272
|
|
|
213
|
-
|
|
214
|
-
does, as it allows you to also store any additional metadata that you might
|
|
215
|
-
want to extract.
|
|
273
|
+
### 1. Add Shrine column
|
|
216
274
|
|
|
217
|
-
|
|
218
|
-
version, making them first-class citizens:
|
|
275
|
+
First we need to create the `image_data` column for Shrine:
|
|
219
276
|
|
|
220
277
|
```rb
|
|
221
|
-
|
|
222
|
-
photo.image[:original].width #=> 800
|
|
223
|
-
|
|
224
|
-
photo.image[:thumb] #=> #<Shrine::UploadedFile>
|
|
225
|
-
photo.image[:thumb].width #=> 300
|
|
278
|
+
add_column :photos, :image_data, :text # or :json or :jsonb if supported
|
|
226
279
|
```
|
|
227
280
|
|
|
228
|
-
|
|
229
|
-
full location each time it wants to generate the URL. That makes it really
|
|
230
|
-
difficult to move files to a new location, because changing how the location is
|
|
231
|
-
generated will now cause incorrect URLs to be generated for all existing files.
|
|
232
|
-
Shrine calculates the whole location only once and saves it to the column.
|
|
233
|
-
|
|
234
|
-
### Multiple uploads
|
|
281
|
+
### 2. Dual write
|
|
235
282
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
using, and it's analogous to how you would implement any nested one-to-many
|
|
240
|
-
associations. Take a look at the [demo app] which shows how easy it is to
|
|
241
|
-
implement multiple uploads.
|
|
242
|
-
|
|
243
|
-
## Migrating from CarrierWave
|
|
244
|
-
|
|
245
|
-
You have an existing app using CarrierWave and you want to transfer it to
|
|
246
|
-
Shrine. Let's assume we have a `Photo` model with the "image" attachment. First
|
|
247
|
-
we need to create the `image_data` column for Shrine:
|
|
283
|
+
Next, we need to make new CarrierWave attachments write to the
|
|
284
|
+
`image_data` column. This can be done by including the below module to all
|
|
285
|
+
models that have CarrierWave attachments:
|
|
248
286
|
|
|
249
287
|
```rb
|
|
250
|
-
|
|
251
|
-
|
|
288
|
+
# config/initializers/shrine.rb (Rails)
|
|
289
|
+
require "shrine"
|
|
290
|
+
|
|
291
|
+
Shrine.storages = {
|
|
292
|
+
cache: ...,
|
|
293
|
+
store: ...,
|
|
294
|
+
}
|
|
252
295
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
attachments:
|
|
296
|
+
Shrine.plugin :model
|
|
297
|
+
Shrine.plugin :derivatives
|
|
256
298
|
|
|
257
|
-
```rb
|
|
258
299
|
module CarrierwaveShrineSynchronization
|
|
259
300
|
def self.included(model)
|
|
260
301
|
model.before_save do
|
|
@@ -266,38 +307,36 @@ module CarrierwaveShrineSynchronization
|
|
|
266
307
|
|
|
267
308
|
def write_shrine_data(name)
|
|
268
309
|
uploader = send(name)
|
|
310
|
+
attacher = Shrine::Attacher.from_model(self, name)
|
|
269
311
|
|
|
270
312
|
if read_attribute(name).present?
|
|
271
|
-
|
|
313
|
+
attacher.set shrine_file(uploader)
|
|
272
314
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
uploader.versions.each do |name, version|
|
|
276
|
-
data[name] = uploader_to_shrine_data(version)
|
|
277
|
-
end
|
|
315
|
+
uploader.versions.each do |version_name, version|
|
|
316
|
+
attacher.merge_derivatives(version_name => shrine_file(version))
|
|
278
317
|
end
|
|
279
|
-
|
|
280
|
-
# Remove the `.to_json` if you're using a JSON column, otherwise the JSON
|
|
281
|
-
# object will be saved as an escaped string.
|
|
282
|
-
write_attribute(:"#{name}_data", data.to_json)
|
|
283
318
|
else
|
|
284
|
-
|
|
319
|
+
attacher.set nil
|
|
285
320
|
end
|
|
286
321
|
end
|
|
287
322
|
|
|
288
323
|
private
|
|
289
324
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
325
|
+
def shrine_file(uploader)
|
|
326
|
+
name = uploader.mounted_as
|
|
327
|
+
filename = read_attribute(name)
|
|
328
|
+
location = uploader.store_path(filename)
|
|
329
|
+
location = location.sub(%r{^#{storage.prefix}/}, "") if storage.prefix
|
|
330
|
+
|
|
331
|
+
Shrine.uploaded_file(
|
|
332
|
+
storage: :store,
|
|
333
|
+
id: location,
|
|
334
|
+
metadata: { "filename" => filename },
|
|
335
|
+
)
|
|
336
|
+
end
|
|
295
337
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
id: path,
|
|
299
|
-
metadata: { filename: filename }
|
|
300
|
-
}
|
|
338
|
+
def storage
|
|
339
|
+
Shrine.storages[:store]
|
|
301
340
|
end
|
|
302
341
|
end
|
|
303
342
|
```
|
|
@@ -309,20 +348,27 @@ end
|
|
|
309
348
|
```
|
|
310
349
|
|
|
311
350
|
After you deploy this code, the `image_data` column should now be successfully
|
|
312
|
-
synchronized with new attachments.
|
|
313
|
-
|
|
351
|
+
synchronized with new attachments.
|
|
352
|
+
|
|
353
|
+
### 3. Data migration
|
|
354
|
+
|
|
355
|
+
Next step is to run a script which writes all existing CarrierWave attachments
|
|
356
|
+
to `image_data`:
|
|
314
357
|
|
|
315
358
|
```rb
|
|
316
359
|
Photo.find_each do |photo|
|
|
317
|
-
|
|
360
|
+
photo.write_shrine_data(:image)
|
|
318
361
|
photo.save!
|
|
319
362
|
end
|
|
320
363
|
```
|
|
321
364
|
|
|
365
|
+
### 4. Rewrite code
|
|
366
|
+
|
|
322
367
|
Now you should be able to rewrite your application so that it uses Shrine
|
|
323
|
-
instead of CarrierWave
|
|
324
|
-
|
|
325
|
-
|
|
368
|
+
instead of CarrierWave (you can consult the reference in the next section). You
|
|
369
|
+
can remove the `CarrierwaveShrineSynchronization` module as well.
|
|
370
|
+
|
|
371
|
+
### 5. Backfill metadata
|
|
326
372
|
|
|
327
373
|
You'll notice that Shrine metadata will be absent from the migrated files'
|
|
328
374
|
data. You can run a script that will fill in any missing metadata defined in
|
|
@@ -332,11 +378,20 @@ your Shrine uploader:
|
|
|
332
378
|
Shrine.plugin :refresh_metadata
|
|
333
379
|
|
|
334
380
|
Photo.find_each do |photo|
|
|
335
|
-
|
|
336
|
-
|
|
381
|
+
attacher = photo.image_attacher
|
|
382
|
+
attacher.refresh_metadata!
|
|
383
|
+
attacher.atomic_persist
|
|
337
384
|
end
|
|
338
385
|
```
|
|
339
386
|
|
|
387
|
+
### 6. Remove CarrierWave column
|
|
388
|
+
|
|
389
|
+
If everything is looking good, we can remove the CarrierWave column:
|
|
390
|
+
|
|
391
|
+
```rb
|
|
392
|
+
remove_column :photos, :image
|
|
393
|
+
```
|
|
394
|
+
|
|
340
395
|
## CarrierWave to Shrine direct mapping
|
|
341
396
|
|
|
342
397
|
### `CarrierWave::Uploader::Base`
|
|
@@ -358,26 +413,28 @@ end
|
|
|
358
413
|
|
|
359
414
|
#### `.process`, `.version`
|
|
360
415
|
|
|
361
|
-
|
|
362
|
-
`Shrine#process` method.
|
|
363
|
-
|
|
364
|
-
#### `.before`, `.after`
|
|
365
|
-
|
|
366
|
-
In Shrine you can get callbacks by loading the `hooks` plugin. Unlike
|
|
367
|
-
CarrierWave, and much like Sequel, Shrine implements callbacks by overriding
|
|
368
|
-
instance methods:
|
|
416
|
+
Processing is defined by using the `derivatives` plugin:
|
|
369
417
|
|
|
370
418
|
```rb
|
|
371
419
|
class ImageUploader < Shrine
|
|
372
|
-
plugin :
|
|
420
|
+
plugin :derivatives
|
|
421
|
+
|
|
422
|
+
Attacher.derivatives do |original|
|
|
423
|
+
magick = ImageProcessing::MiniMagick.source(image)
|
|
373
424
|
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
425
|
+
{
|
|
426
|
+
large: magick.resize_to_limit!(800, 800),
|
|
427
|
+
medium: magick.resize_to_limit!(500, 500),
|
|
428
|
+
small: magick.resize_to_limit!(300, 300),
|
|
429
|
+
}
|
|
377
430
|
end
|
|
378
431
|
end
|
|
379
432
|
```
|
|
380
433
|
|
|
434
|
+
#### `.before`, `.after`
|
|
435
|
+
|
|
436
|
+
There is no Shrine equivalent for CarrierWave's callbacks.
|
|
437
|
+
|
|
381
438
|
#### `#store!`, `#cache!`
|
|
382
439
|
|
|
383
440
|
In Shrine you store and cache files by passing the corresponding storage to
|
|
@@ -406,8 +463,9 @@ uploaded_file.download #=> #<Tempfile:/path/to/file>
|
|
|
406
463
|
In Shrine you call `#url` on uploaded files:
|
|
407
464
|
|
|
408
465
|
```rb
|
|
409
|
-
|
|
410
|
-
|
|
466
|
+
photo.image #=> #<Shrine::UploadedFile>
|
|
467
|
+
photo.image.url #=> "/uploads/398454ujedfggf.jpg"
|
|
468
|
+
photo.image_url #=> "/uploads/398454ujedfggf.jpg" (shorthand)
|
|
411
469
|
```
|
|
412
470
|
|
|
413
471
|
#### `#identifier`
|
|
@@ -415,26 +473,34 @@ user.avatar.url #=> "/uploads/398454ujedfggf.jpg"
|
|
|
415
473
|
This method corresponds to `#original_filename` on the uploaded file:
|
|
416
474
|
|
|
417
475
|
```rb
|
|
418
|
-
|
|
419
|
-
|
|
476
|
+
photo.image #=> #<Shrine::UploadedFile>
|
|
477
|
+
photo.image.original_filename #=> "avatar.jpg"
|
|
420
478
|
```
|
|
421
479
|
|
|
422
480
|
#### `#store_dir`, `#cache_dir`
|
|
423
481
|
|
|
424
|
-
Shrine here provides a `#generate_location` method
|
|
425
|
-
storages:
|
|
482
|
+
Shrine here provides a single `#generate_location` method that's triggered for
|
|
483
|
+
all storages:
|
|
426
484
|
|
|
427
485
|
```rb
|
|
428
486
|
class ImageUploader < Shrine
|
|
429
|
-
def generate_location(io,
|
|
430
|
-
|
|
487
|
+
def generate_location(io, record: nil, name: nil, **)
|
|
488
|
+
[ storage_key,
|
|
489
|
+
record && record.class.name.underscore,
|
|
490
|
+
record && record.id,
|
|
491
|
+
super,
|
|
492
|
+
io.original_filename ].compact.join("/")
|
|
431
493
|
end
|
|
432
494
|
end
|
|
433
495
|
```
|
|
496
|
+
```
|
|
497
|
+
cache/user/123/2feff8c724e7ce17/nature.jpg
|
|
498
|
+
store/user/456/7f99669fde1e01fc/kitten.jpg
|
|
499
|
+
...
|
|
500
|
+
```
|
|
434
501
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
for automatically generating an organized folder structure.
|
|
502
|
+
You might also want to use the `pretty_location` plugin for automatically
|
|
503
|
+
generating an organized folder structure.
|
|
438
504
|
|
|
439
505
|
#### `#default_url`
|
|
440
506
|
|
|
@@ -444,18 +510,15 @@ For default URLs you can use the `default_url` plugin:
|
|
|
444
510
|
class ImageUploader < Shrine
|
|
445
511
|
plugin :default_url
|
|
446
512
|
|
|
447
|
-
Attacher.default_url do |
|
|
448
|
-
"/
|
|
513
|
+
Attacher.default_url do |derivative: nil, **|
|
|
514
|
+
"/fallbacks/#{derivative || "original"}.jpg"
|
|
449
515
|
end
|
|
450
516
|
end
|
|
451
517
|
```
|
|
452
518
|
|
|
453
|
-
The `context` variable holds the name of the attachment, record instance and
|
|
454
|
-
in some cases the `:version`.
|
|
455
|
-
|
|
456
519
|
#### `#extension_white_list`, `#extension_black_list`
|
|
457
520
|
|
|
458
|
-
In Shrine extension whitelisting/blacklisting is a part of validations, and is
|
|
521
|
+
In Shrine, extension whitelisting/blacklisting is a part of validations, and is
|
|
459
522
|
provided by the `validation_helpers` plugin:
|
|
460
523
|
|
|
461
524
|
```rb
|
|
@@ -469,9 +532,9 @@ class ImageUploader < Shrine
|
|
|
469
532
|
end
|
|
470
533
|
```
|
|
471
534
|
|
|
472
|
-
####
|
|
535
|
+
#### `#content_type_whitelist`, `#content_type_blacklist`
|
|
473
536
|
|
|
474
|
-
In Shrine MIME type whitelisting/blacklisting is part of validations, and is
|
|
537
|
+
In Shrine, MIME type whitelisting/blacklisting is part of validations, and is
|
|
475
538
|
provided by the `validation_helpers` plugin, though it doesn't support regexes:
|
|
476
539
|
|
|
477
540
|
```rb
|
|
@@ -485,19 +548,28 @@ class ImageUploader < Shrine
|
|
|
485
548
|
end
|
|
486
549
|
```
|
|
487
550
|
|
|
551
|
+
Make sure to also load the `determine_mime_type` plugin to detect MIME type
|
|
552
|
+
from file content.
|
|
553
|
+
|
|
554
|
+
```rb
|
|
555
|
+
# Gemfile
|
|
556
|
+
gem "mimemagic"
|
|
557
|
+
```
|
|
558
|
+
```rb
|
|
559
|
+
Shrine.plugin :determine_mime_type, analyzer: :mimemagic
|
|
560
|
+
```
|
|
561
|
+
|
|
488
562
|
#### `#size_range`
|
|
489
563
|
|
|
490
564
|
In Shrine file size validations are typically done using the
|
|
491
565
|
`validation_helpers` plugin:
|
|
492
566
|
|
|
493
|
-
|
|
494
567
|
```rb
|
|
495
568
|
class ImageUploader < Shrine
|
|
496
569
|
plugin :validation_helpers
|
|
497
570
|
|
|
498
571
|
Attacher.validate do
|
|
499
|
-
|
|
500
|
-
validate_max_size 5*1024*1024 # 5 MB
|
|
572
|
+
validate_size 0..5*1024*1024 # 5 MB
|
|
501
573
|
end
|
|
502
574
|
end
|
|
503
575
|
```
|
|
@@ -506,13 +578,13 @@ end
|
|
|
506
578
|
|
|
507
579
|
Shrine doesn't have a built-in way of regenerating versions, because that's
|
|
508
580
|
very individual and depends on what versions you want regenerated, what ORM are
|
|
509
|
-
you using, how many records there are in your database etc. The [
|
|
510
|
-
|
|
581
|
+
you using, how many records there are in your database etc. The [Managing
|
|
582
|
+
Derivatives] guide provides some useful tips on this task.
|
|
511
583
|
|
|
512
584
|
### Models
|
|
513
585
|
|
|
514
586
|
The only thing that Shrine requires from your models is a `<attachment>_data`
|
|
515
|
-
column (e.g. if your attachment is "
|
|
587
|
+
column (e.g. if your attachment is "image", you need the `image_data` column).
|
|
516
588
|
|
|
517
589
|
#### `.mount_uploader`
|
|
518
590
|
|
|
@@ -523,7 +595,7 @@ Shrine.plugin :sequel
|
|
|
523
595
|
```
|
|
524
596
|
```rb
|
|
525
597
|
class User < Sequel::Model
|
|
526
|
-
include ImageUploader::Attachment
|
|
598
|
+
include ImageUploader::Attachment(:avatar)
|
|
527
599
|
end
|
|
528
600
|
```
|
|
529
601
|
|
|
@@ -532,7 +604,7 @@ end
|
|
|
532
604
|
The attachment module adds an attachment setter:
|
|
533
605
|
|
|
534
606
|
```rb
|
|
535
|
-
|
|
607
|
+
photo.image = File.open("avatar.jpg", "rb")
|
|
536
608
|
```
|
|
537
609
|
|
|
538
610
|
Note that unlike CarrierWave, you cannot pass in file paths, the input needs to
|
|
@@ -544,8 +616,8 @@ CarrierWave returns the uploader, but Shrine returns a `Shrine::UploadedFile`,
|
|
|
544
616
|
a representation of the file uploaded to the storage:
|
|
545
617
|
|
|
546
618
|
```rb
|
|
547
|
-
|
|
548
|
-
|
|
619
|
+
photo.image #=> #<Shrine::UploadedFile>
|
|
620
|
+
photo.image.methods #=> [:url, :download, :read, :exists?, :delete, ...]
|
|
549
621
|
```
|
|
550
622
|
|
|
551
623
|
If attachment is missing, nil is returned.
|
|
@@ -556,13 +628,13 @@ This method is simply a shorthand for "if attachment is present, call `#url`
|
|
|
556
628
|
on it, otherwise return nil":
|
|
557
629
|
|
|
558
630
|
```rb
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
631
|
+
photo.image_url #=> nil
|
|
632
|
+
photo.image = File.open("avatar.jpg", "rb")
|
|
633
|
+
photo.image_url #=> "/uploads/ksdf934rt.jpg"
|
|
562
634
|
```
|
|
563
635
|
|
|
564
|
-
The `
|
|
565
|
-
argument (`
|
|
636
|
+
The `derivatives` plugin extends this method to also accept a version name as
|
|
637
|
+
the argument (`photo.image_url(:thumb)`).
|
|
566
638
|
|
|
567
639
|
#### `#<attachment>_cache`
|
|
568
640
|
|
|
@@ -573,9 +645,9 @@ that you can use for retaining the cached file:
|
|
|
573
645
|
Shrine.plugin :cached_attachment_data
|
|
574
646
|
```
|
|
575
647
|
```rb
|
|
576
|
-
form_for @
|
|
577
|
-
f.hidden_field :
|
|
578
|
-
f.file_field :
|
|
648
|
+
form_for @photo do |f|
|
|
649
|
+
f.hidden_field :image, value: @photo.cached_image_data, id: nil
|
|
650
|
+
f.file_field :image
|
|
579
651
|
end
|
|
580
652
|
```
|
|
581
653
|
|
|
@@ -594,7 +666,7 @@ shows what are Shrine's equivalents.
|
|
|
594
666
|
|
|
595
667
|
#### `root`, `base_path`, `permissions`, `directory_permissions`
|
|
596
668
|
|
|
597
|
-
In Shrine these are configured on the FileSystem storage directly.
|
|
669
|
+
In Shrine these are configured on the `FileSystem` storage directly.
|
|
598
670
|
|
|
599
671
|
#### `storage`, `storage_engines`
|
|
600
672
|
|
|
@@ -608,7 +680,7 @@ By default Shrine deletes cached and replaced files, but you can choose to keep
|
|
|
608
680
|
those files by loading the `keep_files` plugin:
|
|
609
681
|
|
|
610
682
|
```rb
|
|
611
|
-
Shrine.plugin :keep_files
|
|
683
|
+
Shrine.plugin :keep_files
|
|
612
684
|
```
|
|
613
685
|
|
|
614
686
|
#### `move_to_cache`, `move_to_store`
|
|
@@ -632,8 +704,8 @@ class ImageUploader < Shrine
|
|
|
632
704
|
Attacher.validate do
|
|
633
705
|
# Evaluated inside an instance of Shrine::Attacher.
|
|
634
706
|
if record.guest?
|
|
635
|
-
validate_max_size 2*1024*1024, message: "
|
|
636
|
-
|
|
707
|
+
validate_max_size 2*1024*1024, message: "must not be larger than 2 MB"
|
|
708
|
+
validate_mime_type %w[image/jpg image/png image/webp]
|
|
637
709
|
end
|
|
638
710
|
end
|
|
639
711
|
end
|
|
@@ -661,9 +733,10 @@ multipart or not.
|
|
|
661
733
|
|
|
662
734
|
### `CarrierWave::Storage::Fog`
|
|
663
735
|
|
|
664
|
-
You can use [`Shrine::Storage::S3`]
|
|
665
|
-
[`Shrine::Storage::GoogleCloudStorage`], or generic
|
|
666
|
-
storage. The reference will assume you're
|
|
736
|
+
You can use [`Shrine::Storage::S3`][S3] (built-in),
|
|
737
|
+
[`Shrine::Storage::GoogleCloudStorage`][shrine-gcs], or generic
|
|
738
|
+
[`Shrine::Storage::Fog`][shrine-fog] storage. The reference will assume you're
|
|
739
|
+
using S3 storage.
|
|
667
740
|
|
|
668
741
|
#### `:fog_credentials`, `:fog_directory`
|
|
669
742
|
|
|
@@ -684,7 +757,7 @@ Shrine::Storage::S3.new(
|
|
|
684
757
|
The object data can be configured via the `:upload_options` hash:
|
|
685
758
|
|
|
686
759
|
```rb
|
|
687
|
-
Shrine::Storage::S3.new(upload_options: {content_disposition: "attachment"}, **options)
|
|
760
|
+
Shrine::Storage::S3.new(upload_options: { content_disposition: "attachment" }, **options)
|
|
688
761
|
```
|
|
689
762
|
|
|
690
763
|
#### `:fog_public`
|
|
@@ -692,16 +765,16 @@ Shrine::Storage::S3.new(upload_options: {content_disposition: "attachment"}, **o
|
|
|
692
765
|
The object permissions can be configured with the `:acl` upload option:
|
|
693
766
|
|
|
694
767
|
```rb
|
|
695
|
-
Shrine::Storage::S3.new(upload_options: {acl: "private"}, **options)
|
|
768
|
+
Shrine::Storage::S3.new(upload_options: { acl: "private" }, **options)
|
|
696
769
|
```
|
|
697
770
|
|
|
698
771
|
#### `:fog_authenticated_url_expiration`
|
|
699
772
|
|
|
700
773
|
The `#url` method accepts the `:expires_in` option, you can set the default
|
|
701
|
-
expiration with the `
|
|
774
|
+
expiration with the `url_options` plugin:
|
|
702
775
|
|
|
703
776
|
```rb
|
|
704
|
-
plugin :
|
|
777
|
+
plugin :url_options, store: { expires_in: 600 }
|
|
705
778
|
```
|
|
706
779
|
|
|
707
780
|
#### `:fog_use_ssl_for_aws`, `:fog_aws_accelerate`
|
|
@@ -709,14 +782,12 @@ plugin :default_url_options, store: {expires_in: 600}
|
|
|
709
782
|
Shrine allows you to override the S3 endpoint:
|
|
710
783
|
|
|
711
784
|
```rb
|
|
712
|
-
Shrine::Storage::S3.new(
|
|
785
|
+
Shrine::Storage::S3.new(use_accelerate_endpoint: true, **options)
|
|
713
786
|
```
|
|
714
787
|
|
|
715
|
-
[
|
|
716
|
-
[
|
|
717
|
-
[
|
|
788
|
+
[Managing Derivatives]: https://shrinerb.com/docs/changing-derivatives
|
|
789
|
+
[direct uploads]: https://shrinerb.com/docs/getting-started#direct-uploads
|
|
790
|
+
[S3]: https://shrinerb.com/docs/storage/s3
|
|
791
|
+
[shrine-gcs]: https://github.com/renchap/shrine-google_cloud_storage
|
|
718
792
|
[shrine-fog]: https://github.com/shrinerb/shrine-fog
|
|
719
|
-
[
|
|
720
|
-
[`Shrine::Storage::S3`]: /doc/storage/s3.md#readme
|
|
721
|
-
[`Shrine::Storage::GoogleCloudStorage`]: https://github.com/renchap/shrine-google_cloud_storage
|
|
722
|
-
[`Shrine::Storage::Fog`]: https://github.com/shrinerb/shrine-fog
|
|
793
|
+
[Multiple Files]: https://shrinerb.com/docs/multiple-files
|