shrine 2.19.4 → 3.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +485 -43
- data/LICENSE.txt +1 -1
- data/README.md +81 -977
- 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 +102 -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 +1115 -0
- data/doc/metadata.md +190 -109
- data/doc/multiple_files.md +62 -34
- 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 +162 -101
- data/doc/plugins/derivatives.md +829 -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 +14 -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 +185 -167
- 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 +4 -0
- 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/retrieving_uploads.md +4 -1
- 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 +117 -83
- data/doc/testing.md +124 -144
- data/doc/upgrading_to_3.md +710 -0
- data/doc/validation.md +54 -90
- data/lib/shrine/attacher.rb +287 -171
- 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 +89 -134
- data/lib/shrine/plugins/derivatives.rb +637 -0
- data/lib/shrine/plugins/determine_mime_type.rb +9 -21
- data/lib/shrine/plugins/download_endpoint.rb +109 -133
- data/lib/shrine/plugins/dynamic_storage.rb +5 -11
- data/lib/shrine/plugins/entity.rb +152 -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 +13 -20
- data/lib/shrine/plugins/instrumentation.rb +54 -42
- 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 +158 -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 +18 -22
- 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 +15 -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 +10 -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 +25 -23
- 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 +34 -57
- 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 +154 -158
- data/lib/shrine/uploaded_file.rb +28 -30
- data/lib/shrine/version.rb +3 -3
- data/lib/shrine.rb +86 -149
- data/shrine.gemspec +9 -10
- metadata +79 -83
- 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/plugins/activerecord.md
CHANGED
@@ -1,93 +1,224 @@
|
|
1
|
-
|
1
|
+
---
|
2
|
+
title: Active Record
|
3
|
+
---
|
2
4
|
|
3
|
-
The [`activerecord`][activerecord] plugin
|
4
|
-
|
5
|
+
The [`activerecord`][activerecord] plugin adds [Active Record] integration to
|
6
|
+
the attachment interface. It is built on top of the [`model`][model] plugin.
|
5
7
|
|
6
8
|
```rb
|
7
|
-
plugin :activerecord
|
9
|
+
Shrine.plugin :activerecord
|
8
10
|
```
|
9
11
|
|
10
|
-
##
|
12
|
+
## Attachment
|
11
13
|
|
12
|
-
|
14
|
+
Including a `Shrine::Attachment` module into an `ActiveRecord::Base` subclass
|
15
|
+
will:
|
13
16
|
|
14
|
-
*
|
15
|
-
*
|
16
|
-
|
17
|
+
* add [model] attachment methods
|
18
|
+
* add [validations](#validations) and [callbacks](#callbacks) to tie attachment
|
19
|
+
process to the record lifecycle
|
17
20
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
+
```rb
|
22
|
+
class Photo < ActiveRecord::Base # has `image_data` column
|
23
|
+
include ImageUploader::Attachment(:image) # adds methods, callbacks & validations
|
24
|
+
end
|
25
|
+
```
|
26
|
+
```rb
|
27
|
+
photo = Photo.new
|
28
|
+
|
29
|
+
photo.image = file # cache attachment
|
30
|
+
|
31
|
+
photo.image #=> #<Shrine::UploadedFile id="bc2e13.jpg" storage=:cache ...>
|
32
|
+
photo.image_data #=> '{"id":"bc2e13.jpg","storage":"cache","metadata":{...}}'
|
33
|
+
|
34
|
+
photo.save # persist, promote attachment, then persist again
|
35
|
+
|
36
|
+
photo.image #=> #<Shrine::UploadedFile id="397eca.jpg" storage=:store ...>
|
37
|
+
photo.image_data #=> '{"id":"397eca.jpg","storage":"store","metadata":{...}}'
|
38
|
+
|
39
|
+
photo.destroy # delete attachment
|
40
|
+
|
41
|
+
photo.image.exists? #=> false
|
42
|
+
```
|
43
|
+
|
44
|
+
### Callbacks
|
45
|
+
|
46
|
+
#### After Save
|
47
|
+
|
48
|
+
After a record is saved and the transaction is committed, `Attacher#finalize`
|
49
|
+
is called, which promotes cached file to permanent storage and deletes previous
|
50
|
+
file if any.
|
21
51
|
|
22
52
|
```rb
|
23
|
-
|
24
|
-
|
53
|
+
photo = Photo.new
|
54
|
+
|
55
|
+
photo.image = file
|
56
|
+
photo.image.storage_key #=> :cache
|
57
|
+
|
58
|
+
photo.save
|
59
|
+
photo.image.storage_key #=> :store
|
60
|
+
```
|
61
|
+
|
62
|
+
#### After Destroy
|
63
|
+
|
64
|
+
After a record is destroyed and the transaction is committed,
|
65
|
+
`Attacher#destroy_attached` method is called, which deletes stored attached
|
66
|
+
file if any.
|
67
|
+
|
68
|
+
```rb
|
69
|
+
photo = Photo.find(photo_id)
|
70
|
+
photo.image #=> #<Shrine::UploadedFile>
|
71
|
+
photo.image.exists? #=> true
|
72
|
+
|
73
|
+
photo.destroy
|
74
|
+
photo.image.exists? #=> false
|
25
75
|
```
|
26
76
|
|
27
|
-
|
28
|
-
`backgrounding` plugin.
|
77
|
+
#### Caveats
|
29
78
|
|
30
|
-
|
31
|
-
|
79
|
+
Active Record currently has a [bug with transaction callbacks], so if you have
|
80
|
+
any "after commit" callbacks, make sure to include Shrine's attachment module
|
81
|
+
*after* they have all been defined.
|
82
|
+
|
83
|
+
#### Overriding callbacks
|
84
|
+
|
85
|
+
You can override any of the following attacher methods to modify callback
|
86
|
+
behaviour:
|
87
|
+
|
88
|
+
* `Attacher#activerecord_before_save`
|
89
|
+
* `Attacher#activerecord_after_save`
|
90
|
+
* `Attacher#activerecord_after_destroy`
|
32
91
|
|
33
92
|
```rb
|
34
|
-
class
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
if avatar_data_changed? && avatar_attacher.cached?
|
39
|
-
# cached
|
40
|
-
elsif avatar_data_changed? && avatar_attacher.stored?
|
41
|
-
# promoted
|
42
|
-
end
|
93
|
+
class Shrine::Attacher
|
94
|
+
def activerecord_after_save
|
95
|
+
super
|
96
|
+
# ...
|
43
97
|
end
|
44
98
|
end
|
45
99
|
```
|
46
100
|
|
47
|
-
|
48
|
-
you have any "after commit" callbacks, make sure to include Shrine's attachment
|
49
|
-
module *after* they have all been defined.
|
101
|
+
#### Skipping Callbacks
|
50
102
|
|
51
|
-
If you don't want the attachment module to add any callbacks to
|
52
|
-
|
103
|
+
If you don't want the attachment module to add any callbacks to your model, you
|
104
|
+
can set `:callbacks` to `false`:
|
53
105
|
|
54
106
|
```rb
|
55
107
|
plugin :activerecord, callbacks: false
|
56
108
|
```
|
57
109
|
|
58
|
-
|
110
|
+
### Validations
|
59
111
|
|
60
|
-
|
61
|
-
|
62
|
-
strings, they can also be symbols or symbols and options, which allows them to
|
63
|
-
be internationalized together with other ActiveRecord validation messages.
|
112
|
+
If you're using the [`validation`][validation] plugin, the attachment module
|
113
|
+
will automatically merge attacher errors with model errors.
|
64
114
|
|
65
115
|
```rb
|
66
|
-
class
|
116
|
+
class ImageUploader < Shrine
|
67
117
|
plugin :validation_helpers
|
68
118
|
|
69
119
|
Attacher.validate do
|
70
|
-
validate_max_size
|
120
|
+
validate_max_size 10 * 1024 * 1024
|
71
121
|
end
|
72
122
|
end
|
73
123
|
```
|
124
|
+
```rb
|
125
|
+
photo = Photo.new
|
126
|
+
photo.image = file
|
127
|
+
photo.valid?
|
128
|
+
photo.errors #=> { image: ["size must not be greater than 10.0 MB"] }
|
129
|
+
```
|
130
|
+
|
131
|
+
#### Attachment Presence
|
74
132
|
|
75
|
-
If you want to validate presence of the attachment, you can
|
76
|
-
|
133
|
+
If you want to validate presence of the attachment, you can use Active Record's
|
134
|
+
presence validator:
|
77
135
|
|
78
136
|
```rb
|
79
|
-
class
|
80
|
-
include ImageUploader::Attachment
|
81
|
-
|
137
|
+
class Photo < ActiveRecord::Base
|
138
|
+
include ImageUploader::Attachment(:image)
|
139
|
+
|
140
|
+
validates_presence_of :image
|
82
141
|
end
|
83
142
|
```
|
84
143
|
|
144
|
+
#### I18n
|
145
|
+
|
146
|
+
If you want Active Record to translate attacher error messages, you can use
|
147
|
+
symbols or arrays of symbols and options for validation errors:
|
148
|
+
|
149
|
+
```rb
|
150
|
+
class ImageUploader < Shrine
|
151
|
+
plugin :validation_helpers
|
152
|
+
|
153
|
+
Attacher.validate do
|
154
|
+
validate_max_size 10 * 1024 * 1024, message: -> (max) { [:too_large, max: max] }
|
155
|
+
validate_mime_type %w[image/jpeg image/png], message: :not_image
|
156
|
+
end
|
157
|
+
end
|
158
|
+
```
|
159
|
+
```yml
|
160
|
+
en:
|
161
|
+
activerecord:
|
162
|
+
errors:
|
163
|
+
models:
|
164
|
+
photo:
|
165
|
+
attributes:
|
166
|
+
image:
|
167
|
+
max_size: "must not be larger than %{max_size} bytes"
|
168
|
+
not_image: "must be a common image format"
|
169
|
+
```
|
170
|
+
|
171
|
+
#### Skipping Validations
|
172
|
+
|
85
173
|
If don't want the attachment module to merge file validations errors into
|
86
|
-
model errors, you can
|
174
|
+
model errors, you can set `:validations` to `false`:
|
87
175
|
|
88
176
|
```rb
|
89
177
|
plugin :activerecord, validations: false
|
90
178
|
```
|
91
179
|
|
92
|
-
|
180
|
+
## Attacher
|
181
|
+
|
182
|
+
You can also use `Shrine::Attacher` directly (with or without the
|
183
|
+
`Shrine::Attachment` module):
|
184
|
+
|
185
|
+
```rb
|
186
|
+
class Photo < ActiveRecord::Base # has `image_data` column
|
187
|
+
end
|
188
|
+
```
|
189
|
+
```rb
|
190
|
+
photo = Photo.new
|
191
|
+
attacher = ImageUploader::Attacher.from_model(photo, :image)
|
192
|
+
|
193
|
+
attacher.assign(file) # cache
|
194
|
+
|
195
|
+
attacher.file #=> #<Shrine::UploadedFile id="bc2e13.jpg" storage=:cache ...>
|
196
|
+
photo.image_data #=> '{"id":"bc2e13.jpg","storage":"cache","metadata":{...}}'
|
197
|
+
|
198
|
+
photo.save # persist
|
199
|
+
attacher.finalize # promote
|
200
|
+
photo.save # persist
|
201
|
+
|
202
|
+
attacher.file #=> #<Shrine::UploadedFile id="397eca.jpg" storage=:store ...>
|
203
|
+
photo.image_data #=> '{"id":"397eca.jpg","storage":"store","metadata":{...}}'
|
204
|
+
```
|
205
|
+
|
206
|
+
### Persistence
|
207
|
+
|
208
|
+
The following persistence methods are added to `Shrine::Attacher`:
|
209
|
+
|
210
|
+
| Method | Description |
|
211
|
+
| :----- | :---------- |
|
212
|
+
| `Attacher#atomic_promote` | calls `Attacher#promote` and persists if the attachment hasn't changed |
|
213
|
+
| `Attacher#atomic_persist` | saves changes if the attachment hasn't changed |
|
214
|
+
| `Attacher#persist` | saves any changes to the underlying record |
|
215
|
+
|
216
|
+
See [persistence] docs for more details.
|
217
|
+
|
218
|
+
[activerecord]: https://github.com/shrinerb/shrine/blob/master/lib/shrine/plugins/activerecord.rb
|
219
|
+
[Active Record]: https://guides.rubyonrails.org/active_record_basics.html
|
220
|
+
[model]: https://shrinerb.com/docs/plugins/model
|
221
|
+
[callbacks]: https://guides.rubyonrails.org/active_record_callbacks.html
|
93
222
|
[bug with transaction callbacks]: https://github.com/rails/rails/issues/14493
|
223
|
+
[validation]: https://shrinerb.com/docs/plugins/validation
|
224
|
+
[persistence]: https://shrinerb.com/docs/plugins/persistence
|
data/doc/plugins/add_metadata.md
CHANGED
@@ -1,75 +1,155 @@
|
|
1
|
-
|
1
|
+
---
|
2
|
+
title: Add Metadata
|
3
|
+
---
|
2
4
|
|
3
|
-
The [`add_metadata`][add_metadata] plugin
|
4
|
-
|
5
|
+
The [`add_metadata`][add_metadata] plugin allows adding custom metadata to
|
6
|
+
uploaded files.
|
5
7
|
|
6
8
|
```rb
|
7
|
-
plugin :add_metadata
|
9
|
+
Shrine.plugin :add_metadata
|
10
|
+
```
|
11
|
+
|
12
|
+
## Metadata block
|
13
|
+
|
14
|
+
The `Shrine.add_metadata` method allows you to register a block that will get
|
15
|
+
executed on upload, where you can return custom metadata:
|
16
|
+
|
17
|
+
```rb
|
18
|
+
require "pdf-reader" # https://github.com/yob/pdf-reader
|
8
19
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
{}
|
20
|
+
class PdfUploader < Shrine
|
21
|
+
add_metadata :page_count do |io|
|
22
|
+
reader = PDF::Reader.new(io)
|
23
|
+
reader.page_count
|
14
24
|
end
|
15
25
|
end
|
16
26
|
```
|
17
27
|
|
18
|
-
The above will add
|
19
|
-
reader method on Shrine::UploadedFile
|
28
|
+
The above will add `page_count` key to the metadata hash, and also create the
|
29
|
+
`#page_count` reader method on the `Shrine::UploadedFile`.
|
20
30
|
|
21
31
|
```rb
|
22
|
-
|
32
|
+
uploaded_file.metadata["page_count"] #=> 30
|
23
33
|
# or
|
24
|
-
|
34
|
+
uploaded_file.page_count #=> 30
|
35
|
+
```
|
36
|
+
|
37
|
+
### Skipping nil values
|
38
|
+
|
39
|
+
By default, if your block returns `nil` then the `nil` value will be stored into
|
40
|
+
metadata. If you do not want to store anything when your block returns nil, you
|
41
|
+
can use the `skip_nil: true` option:
|
42
|
+
|
43
|
+
```rb
|
44
|
+
class PdfUploader < Shrine
|
45
|
+
add_metadata :pages, skip_nil: true do |io|
|
46
|
+
if is_pdf?(io)
|
47
|
+
reader = PDF::Reader.new(io)
|
48
|
+
reader.page_count
|
49
|
+
else
|
50
|
+
# If this is not a PDF, then the pages metadata will not be stored
|
51
|
+
nil
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
25
55
|
```
|
26
56
|
|
57
|
+
### Multiple values
|
58
|
+
|
27
59
|
You can also extract multiple metadata values at once, by using `add_metadata`
|
28
60
|
without an argument and returning a hash of metadata.
|
29
61
|
|
30
62
|
```rb
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
63
|
+
require "exif" # https://github.com/tonytonyjan/exif
|
64
|
+
|
65
|
+
class ImageUploader < Shrine
|
66
|
+
add_metadata do |io|
|
67
|
+
begin
|
68
|
+
data = Exif::Data.new(io)
|
69
|
+
rescue Exif::NotReadable # not a valid image
|
70
|
+
next {}
|
71
|
+
end
|
72
|
+
|
73
|
+
{ "date_time" => data.date_time,
|
74
|
+
"flash" => data.flash,
|
75
|
+
"focal_length" => data.focal_length,
|
76
|
+
"exposure_time" => data.exposure_time }
|
36
77
|
end
|
37
|
-
|
38
|
-
{ date_time: data.date_time,
|
39
|
-
flash: data.flash,
|
40
|
-
focal_length: data.focal_length,
|
41
|
-
exposure_time: data.exposure_time }
|
42
78
|
end
|
43
79
|
```
|
80
|
+
```rb
|
81
|
+
uploaded_file.metadata #=>
|
82
|
+
# {
|
83
|
+
# ...
|
84
|
+
# "date_time" => "2019:07:20 16:16:08",
|
85
|
+
# "flash" => 16,
|
86
|
+
# "focal_length" => 26/1,
|
87
|
+
# "exposure_time" => 1/500,
|
88
|
+
# }
|
89
|
+
```
|
44
90
|
|
45
91
|
In this case Shrine won't automatically create reader methods for the extracted
|
46
|
-
metadata
|
47
|
-
`#metadata_method`.
|
92
|
+
metadata, but you can create them via `Shrine.metadata_method`:
|
48
93
|
|
49
94
|
```rb
|
50
|
-
|
95
|
+
class ImageUploader < Shrine
|
96
|
+
# ...
|
97
|
+
metadata_method :date_time, :flash
|
98
|
+
end
|
51
99
|
```
|
100
|
+
```rb
|
101
|
+
uploaded_file.date_time #=> "2019:07:20 16:16:08"
|
102
|
+
uploaded_file.flash #=> 16
|
103
|
+
```
|
104
|
+
|
105
|
+
### Ensuring file
|
52
106
|
|
53
107
|
The `io` might not always be a file object, so if you're using an analyzer
|
54
108
|
which requires the source file to be on disk, you can use `Shrine.with_file` to
|
55
109
|
ensure you have a file object.
|
56
110
|
|
57
111
|
```rb
|
58
|
-
|
59
|
-
|
112
|
+
require "streamio-ffmpeg" # https://github.com/streamio/streamio-ffmpeg
|
113
|
+
|
114
|
+
class VideoUploader < Shrine
|
115
|
+
add_metadata do |io|
|
116
|
+
movie = Shrine.with_file(io) do |file|
|
117
|
+
FFMPEG::Movie.new(file.path)
|
118
|
+
end
|
119
|
+
|
120
|
+
{ "duration" => movie.duration,
|
121
|
+
"bitrate" => movie.bitrate,
|
122
|
+
"resolution" => movie.resolution,
|
123
|
+
"frame_rate" => movie.frame_rate }
|
124
|
+
end
|
125
|
+
end
|
126
|
+
```
|
127
|
+
|
128
|
+
### Uploader options
|
129
|
+
|
130
|
+
Uploader options are also yielded to the block, you can access them for more
|
131
|
+
context:
|
60
132
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
133
|
+
```rb
|
134
|
+
add_metadata do |io, **options|
|
135
|
+
options #=>
|
136
|
+
# {
|
137
|
+
# record: #<Photo>,
|
138
|
+
# name: :image,
|
139
|
+
# action: :store,
|
140
|
+
# metadata: { ... },
|
141
|
+
# ...
|
142
|
+
# }
|
65
143
|
end
|
66
144
|
```
|
67
145
|
|
68
|
-
|
146
|
+
#### Metadata
|
147
|
+
|
148
|
+
The `:metadata` option holds metadata that was extracted so far:
|
69
149
|
|
70
150
|
```rb
|
71
|
-
add_metadata :foo do |io,
|
72
|
-
|
151
|
+
add_metadata :foo do |io, metadata:, **|
|
152
|
+
metadata #=>
|
73
153
|
# {
|
74
154
|
# "size" => 239823,
|
75
155
|
# "filename" => "nature.jpg",
|
@@ -79,8 +159,8 @@ add_metadata :foo do |io, context|
|
|
79
159
|
"foo"
|
80
160
|
end
|
81
161
|
|
82
|
-
add_metadata :bar do |io,
|
83
|
-
|
162
|
+
add_metadata :bar do |io, metadata:, **|
|
163
|
+
metadata #=>
|
84
164
|
# {
|
85
165
|
# "size" => 239823,
|
86
166
|
# "filename" => "nature.jpg",
|
@@ -92,4 +172,25 @@ add_metadata :bar do |io, context|
|
|
92
172
|
end
|
93
173
|
```
|
94
174
|
|
95
|
-
|
175
|
+
## Updating metadata
|
176
|
+
|
177
|
+
If you just wish to add some custom metadata to existing uploads, you can do it
|
178
|
+
with `UploadedFile#add_metadata` (and write the changes back to the model):
|
179
|
+
|
180
|
+
```rb
|
181
|
+
attacher.file.add_metadata("foo" => "bar")
|
182
|
+
attacher.write # write changes to the model attribute
|
183
|
+
|
184
|
+
attacher.file.metadata #=> { ..., "foo" => "bar" }
|
185
|
+
```
|
186
|
+
|
187
|
+
You can also use the `Attacher#add_metadata` shorthand, which also takes care
|
188
|
+
of syncing the model:
|
189
|
+
|
190
|
+
```rb
|
191
|
+
attacher.add_metadata("foo" => "bar")
|
192
|
+
|
193
|
+
attacher.file.metadata #=> { ..., "foo" => "bar" }
|
194
|
+
```
|
195
|
+
|
196
|
+
[add_metadata]: https://github.com/shrinerb/shrine/blob/master/lib/shrine/plugins/add_metadata.rb
|