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/plugins/keep_files.md
CHANGED
|
@@ -1,22 +1,21 @@
|
|
|
1
|
-
|
|
1
|
+
---
|
|
2
|
+
title: Keep Files
|
|
3
|
+
---
|
|
2
4
|
|
|
3
|
-
The [`keep_files`][keep_files] plugin
|
|
4
|
-
from being deleted
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
The plugin accepts the following options:
|
|
9
|
-
|
|
10
|
-
| Option | Description |
|
|
11
|
-
| :------ | :---------- |
|
|
12
|
-
| `:destroyed` | If set to `true`, destroying the record won't delete the associated attachment. |
|
|
13
|
-
| `:replaced` | If set to `true`, uploading a new attachment won't delete the old one. |
|
|
14
|
-
|
|
15
|
-
For example, the following will keep destroyed and replaced files:
|
|
5
|
+
The [`keep_files`][keep_files] plugin prevents the attached file (and any of
|
|
6
|
+
its [derivatives]) from being deleted when the attachment would normally be
|
|
7
|
+
destroyed, which happens when the attachment is removed/replaced, or when the
|
|
8
|
+
record is deleted. This functionality is useful when implementing soft deletes,
|
|
9
|
+
versioning, or in general any scenario where you need to keep history.
|
|
16
10
|
|
|
17
11
|
```rb
|
|
18
|
-
plugin :keep_files
|
|
12
|
+
plugin :keep_files
|
|
13
|
+
```
|
|
14
|
+
```rb
|
|
15
|
+
photo.image #=> #<Shrine::UploadedFile>
|
|
16
|
+
photo.destroy
|
|
17
|
+
photo.image.exists? #=> true
|
|
19
18
|
```
|
|
20
19
|
|
|
21
|
-
[keep_files]: /lib/shrine/plugins/keep_files.rb
|
|
22
|
-
[
|
|
20
|
+
[keep_files]: https://github.com/shrinerb/shrine/blob/master/lib/shrine/plugins/keep_files.rb
|
|
21
|
+
[derivatives]: https://shrinerb.com/docs/plugins/derivatives
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
---
|
|
2
|
+
title: Metadata Attributes
|
|
3
|
+
---
|
|
2
4
|
|
|
3
|
-
The [`metadata_attributes`][metadata_attributes] plugin allows you to
|
|
4
|
-
attachment metadata to additional record attributes. You can
|
|
5
|
-
|
|
6
|
-
method:
|
|
5
|
+
The [`metadata_attributes`][metadata_attributes] plugin allows you to write
|
|
6
|
+
attachment metadata to additional record attributes. You can configure the
|
|
7
|
+
plugin with a hash of mappings:
|
|
7
8
|
|
|
8
9
|
```rb
|
|
9
10
|
plugin :metadata_attributes, :size => :size, :mime_type => :type
|
|
@@ -12,7 +13,7 @@ plugin :metadata_attributes
|
|
|
12
13
|
Attacher.metadata_attributes :size => :size, :mime_type => :type
|
|
13
14
|
```
|
|
14
15
|
|
|
15
|
-
The above configuration will
|
|
16
|
+
The above configuration will write `size` metadata field to `<attachment>_size`
|
|
16
17
|
record attribute, and `mime_type` metadata field to `<attachment>_type` record
|
|
17
18
|
attribute.
|
|
18
19
|
|
|
@@ -28,19 +29,47 @@ user.avatar_size #=> nil
|
|
|
28
29
|
user.avatar_type #=> nil
|
|
29
30
|
```
|
|
30
31
|
|
|
32
|
+
## Model and Entity
|
|
33
|
+
|
|
34
|
+
With the [`model`][model] plugin, any method that internally calls
|
|
35
|
+
`Attacher#write` will trigger metadata attributes writing (`Attacher#assign`,
|
|
36
|
+
`Attacher#attach`, `Attacher#change`, `Attacher#set`).
|
|
37
|
+
|
|
38
|
+
```rb
|
|
39
|
+
attacher.file.metadata["mime_type"] = "other/type"
|
|
40
|
+
attacher.write
|
|
41
|
+
attacher.record.avatar_type #=> "other/type"
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
If you're using the [`entity`][entity] plugin, metadata attributes will be
|
|
45
|
+
added to `Attacher#column_values`:
|
|
46
|
+
|
|
47
|
+
```rb
|
|
48
|
+
attacher.assign(io)
|
|
49
|
+
attacher.column_values #=>
|
|
50
|
+
# {
|
|
51
|
+
# :image_data => '{ ... }',
|
|
52
|
+
# :image_size => 95724,
|
|
53
|
+
# :image_type => "image/jpeg",
|
|
54
|
+
# }
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Any metadata attributes that were declared but are missing on the record will
|
|
58
|
+
be skipped.
|
|
59
|
+
|
|
60
|
+
## Full attribute name
|
|
61
|
+
|
|
31
62
|
If you want to specify the full record attribute name, pass the record
|
|
32
63
|
attribute name as a string instead of a symbol.
|
|
33
64
|
|
|
34
65
|
```rb
|
|
35
66
|
Attacher.metadata_attributes :filename => "original_filename"
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
67
|
+
```
|
|
68
|
+
```rb
|
|
39
69
|
photo.image = image
|
|
40
70
|
photo.original_filename #=> "nature.jpg"
|
|
41
71
|
```
|
|
42
72
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
[metadata_attributes]: /lib/shrine/plugins/metadata_attributes.rb
|
|
73
|
+
[metadata_attributes]: https://github.com/shrinerb/shrine/blob/master/lib/shrine/plugins/metadata_attributes.rb
|
|
74
|
+
[entity]: https://shrinerb.com/docs/plugins/entity
|
|
75
|
+
[model]: https://shrinerb.com/docs/plugins/model
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Mirroring
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
The [`mirroring`][mirroring] plugin enables replicating uploads and deletes to
|
|
6
|
+
other storages. This can be useful for setting up a backup storage, or when
|
|
7
|
+
migrating files from one storage to another.
|
|
8
|
+
|
|
9
|
+
```rb
|
|
10
|
+
Shrine.plugin :mirroring, mirror: { store: :other_store }
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
With the above setup, any upload and delete to `:store` will be replicated to
|
|
14
|
+
`:other_store`.
|
|
15
|
+
|
|
16
|
+
```rb
|
|
17
|
+
file = Shrine.upload(io, :store) # uploads to :store and :other_store
|
|
18
|
+
file.delete # deletes from :store and :other_store
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
You can skip mirroring for a specific upload/delete call by passing `mirror:
|
|
22
|
+
false`:
|
|
23
|
+
|
|
24
|
+
```rb
|
|
25
|
+
file = Shrine.upload(io, :store, mirror: false) # skips mirroring
|
|
26
|
+
file.delete(mirror: false) # skips mirroring
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Multiple storages
|
|
30
|
+
|
|
31
|
+
You can mirror to multiple storages by specifying an array:
|
|
32
|
+
|
|
33
|
+
```rb
|
|
34
|
+
Shrine.plugin :mirroring, mirror: {
|
|
35
|
+
store: [:other_store_1, :other_store_2]
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Backup storage
|
|
40
|
+
|
|
41
|
+
If you want the mirror storage to act as a backup, you can disable mirroring
|
|
42
|
+
deletes:
|
|
43
|
+
|
|
44
|
+
```rb
|
|
45
|
+
Shrine.plugin :mirroring, mirror: { ... }, delete: false
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Backgrounding
|
|
49
|
+
|
|
50
|
+
You can have mirroring performed in a background job:
|
|
51
|
+
|
|
52
|
+
```rb
|
|
53
|
+
Shrine.mirror_upload_block do |file, **options|
|
|
54
|
+
MirrorUploadJob.perform_async(file.shrine_class.name, file.data)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
Shrine.mirror_delete_block do |file|
|
|
58
|
+
MirrorDeleteJob.perform_async(file.shrine_class.name, file.data)
|
|
59
|
+
end
|
|
60
|
+
```
|
|
61
|
+
```rb
|
|
62
|
+
class MirrorUploadJob
|
|
63
|
+
include Sidekiq::Worker
|
|
64
|
+
|
|
65
|
+
def perform(shrine_class, file_data)
|
|
66
|
+
shrine_class = Object.const_get(shrine_class)
|
|
67
|
+
|
|
68
|
+
file = shrine_class.uploaded_file(file_data)
|
|
69
|
+
file.mirror_upload
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
```
|
|
73
|
+
```rb
|
|
74
|
+
class MirrorDeleteJob
|
|
75
|
+
include Sidekiq::Worker
|
|
76
|
+
|
|
77
|
+
def perform(shrine_class, file_data)
|
|
78
|
+
shrine_class = Object.const_get(shrine_class)
|
|
79
|
+
|
|
80
|
+
file = shrine_class.uploaded_file(file_data)
|
|
81
|
+
file.mirror_delete
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## API
|
|
87
|
+
|
|
88
|
+
You can disable automatic mirroring and perform mirroring manually:
|
|
89
|
+
|
|
90
|
+
```rb
|
|
91
|
+
# disable automatic mirroring of uploads and deletes
|
|
92
|
+
Shrine.plugin :mirroring, mirror: { ... }, upload: false, delete: false
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
To perform mirroring, you can call `UploadedFile#mirror_upload` and
|
|
96
|
+
`UploadedFile#mirror_delete`:
|
|
97
|
+
|
|
98
|
+
```rb
|
|
99
|
+
file = Shrine.upload(io, :store) # upload to :store
|
|
100
|
+
file.mirror_upload # upload to :other_store
|
|
101
|
+
|
|
102
|
+
file.delete # delete from :store
|
|
103
|
+
file.mirror_delete # delete from :other_store
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
If you've set up backgrounding, you can use
|
|
107
|
+
`UploadedFile#mirror_upload_background` and
|
|
108
|
+
`UploadedFile#mirror_delete_background` to call the background block instead:
|
|
109
|
+
|
|
110
|
+
```rb
|
|
111
|
+
file = Shrine.upload(io, :store) # upload to :store
|
|
112
|
+
file.mirror_upload_background # spawn mirror upload background job
|
|
113
|
+
|
|
114
|
+
file.delete # delete from :store
|
|
115
|
+
file.mirror_delete_background # spawn mirror delete background job
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
[mirroring]: https://github.com/shrinerb/shrine/blob/master/lib/shrine/plugins/mirroring.rb
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Model
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
The [`model`][model] plugin provides integration for handling attachment on
|
|
6
|
+
mutable structs. It is built on top of the [`entity`][entity] plugin.
|
|
7
|
+
|
|
8
|
+
```rb
|
|
9
|
+
plugin :model
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Attachment
|
|
13
|
+
|
|
14
|
+
Including a `Shrine::Attachment` module into a model class will:
|
|
15
|
+
|
|
16
|
+
* add [entity] attachment methods
|
|
17
|
+
* add `#<name>=` and `#<name>_changed?` methods
|
|
18
|
+
|
|
19
|
+
```rb
|
|
20
|
+
class Photo
|
|
21
|
+
attr_accessor :image_data
|
|
22
|
+
|
|
23
|
+
include ImageUploader::Attachment(:image)
|
|
24
|
+
end
|
|
25
|
+
```
|
|
26
|
+
```rb
|
|
27
|
+
photo = Photo.new
|
|
28
|
+
|
|
29
|
+
photo.image = file
|
|
30
|
+
|
|
31
|
+
photo.image #=> #<Shrine::UploadedFile id="bc2e13.jpg" storage=:cache ...>
|
|
32
|
+
photo.image_data #=> '{"id":"bc2e13.jpg","storage":"cache","metadata":{...}}'
|
|
33
|
+
|
|
34
|
+
photo.image_attacher.finalize
|
|
35
|
+
|
|
36
|
+
photo.image #=> #<Shrine::UploadedFile id="397eca.jpg" storage=:store ...>
|
|
37
|
+
photo.image_data #=> '{"id":"397eca.jpg","storage":"store","metadata":{...}}'
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
#### `#<name>=`
|
|
41
|
+
|
|
42
|
+
Calls `Attacher#assign` by default, which uploads the file to temporary storage
|
|
43
|
+
and attaches it, updating the model attribute.
|
|
44
|
+
|
|
45
|
+
```rb
|
|
46
|
+
photo = Photo.new
|
|
47
|
+
photo.image = file
|
|
48
|
+
photo.image.storage_key #=> :cache
|
|
49
|
+
photo.image_data #=> '{"id":"...","storage":"cache","metadata":{...}}'
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
#### `#<name>_changed?`
|
|
53
|
+
|
|
54
|
+
Calls `Attacher#changed?` which returns whether the attachment has changed.
|
|
55
|
+
|
|
56
|
+
```rb
|
|
57
|
+
photo = Photo.new
|
|
58
|
+
photo.image_changed? #=> false
|
|
59
|
+
photo.image = file
|
|
60
|
+
photo.image_changed? #=> true
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
#### Disabling caching
|
|
64
|
+
|
|
65
|
+
If you don't want to use temporary storage, you can have `#<name>=` upload
|
|
66
|
+
directly to permanent storage.
|
|
67
|
+
|
|
68
|
+
```rb
|
|
69
|
+
plugin :model, cache: false
|
|
70
|
+
```
|
|
71
|
+
```rb
|
|
72
|
+
photo = Photo.new
|
|
73
|
+
photo.image = file
|
|
74
|
+
photo.image.storage_key #=> :store
|
|
75
|
+
photo.image_data #=> '{"id":"...","storage":"store","metadata":{...}}'
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
This can be configured on the attacher level as well:
|
|
79
|
+
|
|
80
|
+
```rb
|
|
81
|
+
photo = Photo.new
|
|
82
|
+
photo.image_attacher(model_cache: false)
|
|
83
|
+
photo.image = file
|
|
84
|
+
photo.image.storage_key #=> :store
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
#### `#<name>_attacher`
|
|
88
|
+
|
|
89
|
+
Returns an `Attacher` instance backed by the model instance, memoized in an
|
|
90
|
+
instance variable.
|
|
91
|
+
|
|
92
|
+
```rb
|
|
93
|
+
photo = Photo.new
|
|
94
|
+
photo.image_attacher #=> #<ImageUploader::Attacher> (memoizes the instance)
|
|
95
|
+
photo.image_attacher #=> #<ImageUploader::Attacher> (returns memoized instance)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
When attacher options are passed, the attacher instance is refreshed:
|
|
99
|
+
|
|
100
|
+
```rb
|
|
101
|
+
photo = Photo.new
|
|
102
|
+
photo.image_attacher(cache: :other_cache)
|
|
103
|
+
photo.image_attacher.cache_key #=> :other_cache
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Entity
|
|
107
|
+
|
|
108
|
+
If you still want to include `Shrine::Attachment` modules to immutable
|
|
109
|
+
entities, you can disable "model" behaviour by passing `model: false`:
|
|
110
|
+
|
|
111
|
+
```rb
|
|
112
|
+
class Photo
|
|
113
|
+
attr_reader :image_data
|
|
114
|
+
|
|
115
|
+
include ImageUploader::Attachment(:image, model: false)
|
|
116
|
+
end
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Attacher
|
|
120
|
+
|
|
121
|
+
You can also use `Shrine::Attacher` directly (with or without the
|
|
122
|
+
`Shrine::Attachment` module):
|
|
123
|
+
|
|
124
|
+
```rb
|
|
125
|
+
class Photo
|
|
126
|
+
attr_accessor :image_data
|
|
127
|
+
end
|
|
128
|
+
```
|
|
129
|
+
```rb
|
|
130
|
+
photo = Photo.new
|
|
131
|
+
attacher = ImageUploader::Attacher.from_model(photo, :image)
|
|
132
|
+
|
|
133
|
+
attacher.assign(file) # cache
|
|
134
|
+
|
|
135
|
+
attacher.file #=> #<Shrine::UploadedFile id="bc2e13.jpg" storage=:cache ...>
|
|
136
|
+
photo.image_data #=> '{"id":"bc2e13.jpg","storage":"cache","metadata":{...}}'
|
|
137
|
+
|
|
138
|
+
attacher.finalize # promote
|
|
139
|
+
|
|
140
|
+
attacher.file #=> #<Shrine::UploadedFile id="397eca.jpg" storage=:store ...>
|
|
141
|
+
photo.image_data #=> '{"id":"397eca.jpg","storage":"store","metadata":{...}}'
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Loading model
|
|
145
|
+
|
|
146
|
+
The `Attacher.from_model` method can be used for creating an `Attacher`
|
|
147
|
+
instance backed by a model object.
|
|
148
|
+
|
|
149
|
+
```rb
|
|
150
|
+
photo = Photo.new
|
|
151
|
+
attacher = ImageUploader::Attacher.from_model(photo, :image)
|
|
152
|
+
|
|
153
|
+
attacher.record #=> #<Photo>
|
|
154
|
+
attacher.name #=> :image
|
|
155
|
+
attacher.attribute #=> :image_data
|
|
156
|
+
|
|
157
|
+
attacher.attach(io)
|
|
158
|
+
photo.image_data #=> '{"id":"...","storage":"...","metadata":{...}}'
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
You can also load an entity into an existing attacher with
|
|
162
|
+
`Attacher#load_model`.
|
|
163
|
+
|
|
164
|
+
```rb
|
|
165
|
+
photo = Photo.new(image_data: '{"id":"...","storage":"...","metadata":{...}}')
|
|
166
|
+
|
|
167
|
+
attacher.file #=> nil
|
|
168
|
+
attacher.load_model(photo, :image)
|
|
169
|
+
attacher.file #=> #<ImageUploader::UploadedFile>
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Or just `Attacher#set_model` if you don't want to load attachment data:
|
|
173
|
+
|
|
174
|
+
```rb
|
|
175
|
+
photo = Photo.new(image_data: '{"id":"...","storage":"...","metadata":{...}}')
|
|
176
|
+
|
|
177
|
+
attacher.file #=> nil
|
|
178
|
+
attacher.set_model(photo, :image) # doesn't load attachment data
|
|
179
|
+
attacher.file #=> nil
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Writing attachment data
|
|
183
|
+
|
|
184
|
+
The `Attacher#write` method writes attachment data to the `#<name>_data`
|
|
185
|
+
attribute on the model instance.
|
|
186
|
+
|
|
187
|
+
```rb
|
|
188
|
+
photo = Photo.new
|
|
189
|
+
attacher = ImageUploader::Attacher.from_model(photo, :image)
|
|
190
|
+
|
|
191
|
+
attacher.file = uploaded_file
|
|
192
|
+
photo.image_data #=> nil
|
|
193
|
+
|
|
194
|
+
attacher.write
|
|
195
|
+
photo.image_data #=> '{"id":"...","storage":"...","metadata":{...}}'
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
The `Attacher#write` method is automatically called on `Attacher#set`, as well
|
|
199
|
+
as `Attacher#assign`, `Attacher#attach_cached`, `Attacher#attach`,
|
|
200
|
+
`Attacher#promote` and any other attacher method that calls `Attacher#set`.
|
|
201
|
+
|
|
202
|
+
## Serialization
|
|
203
|
+
|
|
204
|
+
By default, attachment data is serialized into JSON using the `JSON` standard
|
|
205
|
+
library. If you want to change how data is serialized, see the
|
|
206
|
+
[`column`][column serializer] plugin docs.
|
|
207
|
+
|
|
208
|
+
[model]: https://github.com/shrinerb/shrine/blob/master/lib/shrine/plugins/model.rb
|
|
209
|
+
[entity]: https://shrinerb.com/docs/plugins/entity
|
|
210
|
+
[column serializer]: https://shrinerb.com/docs/plugins/column#serializer
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
---
|
|
2
|
+
title: Module Include
|
|
3
|
+
---
|
|
2
4
|
|
|
3
5
|
The [`module_include`][module_include] plugin allows you to extend Shrine's
|
|
4
6
|
core classes for the given uploader with modules/methods.
|
|
@@ -39,4 +41,4 @@ end
|
|
|
39
41
|
The above defines an additional `#<attachment>_size` method on the attachment
|
|
40
42
|
module, which is what is included in your model.
|
|
41
43
|
|
|
42
|
-
[module_include]: /lib/shrine/plugins/module_include.rb
|
|
44
|
+
[module_include]: https://github.com/shrinerb/shrine/blob/master/lib/shrine/plugins/module_include.rb
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Multi Cache
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
The [`multi_cache`][multi_cache] plugin allows an attacher to accept files from
|
|
6
|
+
additional temporary storages.
|
|
7
|
+
|
|
8
|
+
```rb
|
|
9
|
+
Shrine.storages = { cache: ..., cache_one: ..., cache_two: ..., store: ... }
|
|
10
|
+
|
|
11
|
+
Shrine.plugin :multi_cache, additional_cache: [:cache_one, :cache_two]
|
|
12
|
+
```
|
|
13
|
+
```rb
|
|
14
|
+
photo.image = { "id" => "...", "storage" => "cache", "metadata" => { ... } }
|
|
15
|
+
photo.image.storage_key #=> :cache
|
|
16
|
+
# or
|
|
17
|
+
photo.image = { "id" => "...", "storage" => "cache_one", "metadata" => { ... } }
|
|
18
|
+
photo.image.storage_key #=> :cache_one
|
|
19
|
+
# or
|
|
20
|
+
photo.image = { "id" => "...", "storage" => "cache_two", "metadata" => { ... } }
|
|
21
|
+
photo.image.storage_key #=> :cache_two
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
[multi_cache]: https://github.com/shrinerb/shrine/blob/master/lib/shrine/plugins/multi_cache.rb
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Persistence
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
This is an internal plugin that provides uniform persistence interface across
|
|
6
|
+
different persistence plugins (e.g. [`activerecord`][activerecord],
|
|
7
|
+
[`sequel`][sequel]).
|
|
8
|
+
|
|
9
|
+
For these activerecord and sequel, atomic persistence is implemented in terms
|
|
10
|
+
of database locks, eg "SELECT... FOR UPDATE". For more discussion of concurrency
|
|
11
|
+
challenges, see the [atomic_helpers] documentation.
|
|
12
|
+
|
|
13
|
+
## Atomic promotion
|
|
14
|
+
|
|
15
|
+
If you're promoting cached file to permanent storage
|
|
16
|
+
[asynchronously][backgrounding], and want to handle the possibility of
|
|
17
|
+
attachment changing during promotion, you can use `Attacher#atomic_promote`:
|
|
18
|
+
|
|
19
|
+
```rb
|
|
20
|
+
# in your controller
|
|
21
|
+
attacher.attach_cached(io)
|
|
22
|
+
attacher.cached? #=> true
|
|
23
|
+
```
|
|
24
|
+
```rb
|
|
25
|
+
# in a background job
|
|
26
|
+
attacher.atomic_promote # promotes cached file and persists
|
|
27
|
+
attacher.stored? #=> true
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
After the cached file is uploaded to permanent storage, the record is reloaded
|
|
31
|
+
in order to check whether the attachment hasn't changed, and if it hasn't the
|
|
32
|
+
attachment is persisted. If the attachment has changed,
|
|
33
|
+
`Shrine::AttachmentChanged` exception is raised.
|
|
34
|
+
|
|
35
|
+
If you want to execute code after the attachment change check but before
|
|
36
|
+
persistence, you can pass a block:
|
|
37
|
+
|
|
38
|
+
```rb
|
|
39
|
+
attacher.atomic_promote do |reloaded_attacher|
|
|
40
|
+
# run code after attachment change check but before persistence
|
|
41
|
+
end
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
You can pass `:reload` and `:persist` options to change how the record is
|
|
45
|
+
reloaded and pesisted. See the [`atomic_helpers`][atomic_helpers] plugin docs
|
|
46
|
+
for more details.
|
|
47
|
+
|
|
48
|
+
Any other options are forwarded to `Attacher#promote`:
|
|
49
|
+
|
|
50
|
+
```rb
|
|
51
|
+
attacher.atomic_promote(metadata: true) # re-extract metadata
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Atomic persistence
|
|
55
|
+
|
|
56
|
+
If you're updating something based on the attached file
|
|
57
|
+
[asynchronously][backgrounding], you might want to handle the possibility of
|
|
58
|
+
the attachment changing in the meanwhile. You can do that with
|
|
59
|
+
`Attacher#atomic_persist`:
|
|
60
|
+
|
|
61
|
+
```rb
|
|
62
|
+
# in a background job
|
|
63
|
+
attacher.refresh_metadata! # refresh_metadata plugin
|
|
64
|
+
attacher.atomic_persist # persists attachment data
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
The record is first reloaded in order to check whether the attachment hasn't
|
|
68
|
+
changed, and if it hasn't the attachment is persisted. If the attachment has
|
|
69
|
+
changed, `Shrine::AttachmentChanged` exception is raised.
|
|
70
|
+
|
|
71
|
+
If you want to execute code after the attachment change check but before
|
|
72
|
+
persistence, you can pass a block. For instance, one way to allow concurrent
|
|
73
|
+
changes to metadata, perhaps in different background workers, without
|
|
74
|
+
overwriting each other might be:
|
|
75
|
+
|
|
76
|
+
```rb
|
|
77
|
+
attacher.atomic_persist do |reloaded_attacher|
|
|
78
|
+
# run code after attachment change check but before persistence
|
|
79
|
+
attacher.file.metadata.merge!(reloaded_attacher.file.metadata)
|
|
80
|
+
attacher.file.metadata["some_key"] = "changed_value"
|
|
81
|
+
end
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
You can pass `:reload` and `:persist` options to change how the record is
|
|
85
|
+
reloaded and pesisted. See the [`atomic_helpers`][atomic_helpers] plugin docs
|
|
86
|
+
for more details.
|
|
87
|
+
|
|
88
|
+
## Simple Persistence
|
|
89
|
+
|
|
90
|
+
To simply save attachment changes to the underlying record, use
|
|
91
|
+
`Attacher#persist`:
|
|
92
|
+
|
|
93
|
+
```rb
|
|
94
|
+
attacher.attach(io)
|
|
95
|
+
attacher.persist # saves the underlying record
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
[activerecord]: https://shrinerb.com/docs/plugins/activerecord
|
|
99
|
+
[sequel]: https://shrinerb.com/docs/plugins/sequel
|
|
100
|
+
[atomic_helpers]: https://shrinerb.com/docs/plugins/atomic_helpers
|
|
101
|
+
[backgrounding]: https://shrinerb.com/docs/plugins/backgrounding
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
---
|
|
2
|
+
title: Presign Endpoint
|
|
3
|
+
---
|
|
2
4
|
|
|
3
5
|
The [`presign_endpoint`][presign_endpoint] plugin provides a Rack endpoint
|
|
4
6
|
which generates the URL, fields, and headers that can be used to upload files
|
|
@@ -11,6 +13,8 @@ more.
|
|
|
11
13
|
plugin :presign_endpoint
|
|
12
14
|
```
|
|
13
15
|
|
|
16
|
+
## Setup
|
|
17
|
+
|
|
14
18
|
The plugin adds a `Shrine.presign_endpoint` method which, given a storage
|
|
15
19
|
identifier, returns a Rack application that accepts GET requests and generates
|
|
16
20
|
a presign for the specified storage. You can run this Rack application inside
|
|
@@ -60,7 +64,7 @@ create a custom controller action and handle presign requests there using
|
|
|
60
64
|
# config/routes.rb (Rails)
|
|
61
65
|
Rails.application.routes.draw do
|
|
62
66
|
# ...
|
|
63
|
-
|
|
67
|
+
get "/images/presign", to: "presigns#image"
|
|
64
68
|
end
|
|
65
69
|
```
|
|
66
70
|
```rb
|
|
@@ -130,7 +134,8 @@ option:
|
|
|
130
134
|
|
|
131
135
|
```rb
|
|
132
136
|
plugin :presign_endpoint, presign: -> (id, options, request) do
|
|
133
|
-
# return a Hash with :url, :fields, and :headers keys
|
|
137
|
+
# return a Hash with :method, :url, :fields, and :headers keys
|
|
138
|
+
Shrine.storages[:cache].presign(id, options)
|
|
134
139
|
end
|
|
135
140
|
```
|
|
136
141
|
|
|
@@ -156,7 +161,7 @@ Shrine.presign_endpoint(:cache, presign_location: "${filename}")
|
|
|
156
161
|
Shrine.presign_response(:cache, env, presign_location: "${filename}")
|
|
157
162
|
```
|
|
158
163
|
|
|
159
|
-
[presign_endpoint]: /lib/shrine/plugins/presign_endpoint.rb
|
|
164
|
+
[presign_endpoint]: https://github.com/shrinerb/shrine/blob/master/lib/shrine/plugins/presign_endpoint.rb
|
|
160
165
|
[Uppy]: https://uppy.io
|
|
161
166
|
[Amazon S3]: https://aws.amazon.com/s3/
|
|
162
167
|
[Google Cloud Storage]: https://cloud.google.com/storage/
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
---
|
|
2
|
+
title: Pretty Location
|
|
3
|
+
---
|
|
2
4
|
|
|
3
5
|
The [`pretty_location`][pretty_location] plugin attempts to generate a nicer
|
|
4
6
|
folder structure for uploaded files.
|
|
@@ -13,7 +15,7 @@ generated locations will typically look like this:
|
|
|
13
15
|
|
|
14
16
|
```rb
|
|
15
17
|
"user/564/avatar/thumb-493g82jf23.jpg"
|
|
16
|
-
# :model/:id/:attachment/:
|
|
18
|
+
# :model/:id/:attachment/:derivative-:uid.:extension
|
|
17
19
|
```
|
|
18
20
|
|
|
19
21
|
By default if a record class is inside a namespace, only the "inner" class name
|
|
@@ -40,6 +42,17 @@ plugin :pretty_location, identifier: :email
|
|
|
40
42
|
# "user/foo@bar.com/profile_picture/493g82jf23.jpg"
|
|
41
43
|
```
|
|
42
44
|
|
|
45
|
+
By default, the class name will be only downcased. We can also have the class
|
|
46
|
+
name underscored with the `:class_underscore` option:
|
|
47
|
+
|
|
48
|
+
```ruby
|
|
49
|
+
plugin :pretty_location
|
|
50
|
+
# "blogpost/aa357797-5845-451b-8662-08eecdc9f762/image/493g82jf23.jpg"
|
|
51
|
+
|
|
52
|
+
plugin :pretty_location, class_underscore: :true
|
|
53
|
+
# "blog_post/aa357797-5845-451b-8662-08eecdc9f762/image/493g82jf23.jpg"
|
|
54
|
+
```
|
|
55
|
+
|
|
43
56
|
For a more custom identifier logic, you can overwrite the method
|
|
44
57
|
`#generate_location` and call `#pretty_location` with the identifier you have
|
|
45
58
|
calculated.
|
|
@@ -51,4 +64,4 @@ def generate_location(io, record: nil, **context)
|
|
|
51
64
|
end
|
|
52
65
|
```
|
|
53
66
|
|
|
54
|
-
[pretty_location]: /lib/shrine/plugins/pretty_location.rb
|
|
67
|
+
[pretty_location]: https://github.com/shrinerb/shrine/blob/master/lib/shrine/plugins/pretty_location.rb
|
data/doc/plugins/processing.md
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
---
|
|
2
|
+
title: Processing
|
|
3
|
+
---
|
|
2
4
|
|
|
3
5
|
Shrine uploaders can define the `#process` method, which will get called
|
|
4
6
|
whenever a file is uploaded. It is given the original file, and is expected to
|
|
@@ -65,5 +67,5 @@ uploader.process(file, action: :store) # only process
|
|
|
65
67
|
If you want the result of processing to be multiple files, use the `versions`
|
|
66
68
|
plugin.
|
|
67
69
|
|
|
68
|
-
[processing]: /lib/shrine/plugins/processing.rb
|
|
70
|
+
[processing]: https://github.com/shrinerb/shrine/blob/master/lib/shrine/plugins/processing.rb
|
|
69
71
|
[image_processing]: https://github.com/janko/image_processing
|