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/keep_files.md
CHANGED
@@ -1,22 +1,19 @@
|
|
1
|
-
|
1
|
+
---
|
2
|
+
title: Keep Files
|
3
|
+
---
|
2
4
|
|
3
|
-
The [`keep_files`][keep_files] plugin
|
4
|
-
|
5
|
-
|
6
|
-
track history.
|
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 file deletion when the attacher
|
6
|
+
is about to destroy currently attached or previously attached file. This
|
7
|
+
functionality is useful when implementing soft deletes, versioning, or in
|
8
|
+
general any scenario where you need to track history.
|
16
9
|
|
17
10
|
```rb
|
18
|
-
plugin :keep_files
|
11
|
+
plugin :keep_files
|
12
|
+
```
|
13
|
+
```rb
|
14
|
+
photo.image #=> #<Shrine::UploadedFile>
|
15
|
+
photo.destroy
|
16
|
+
photo.image.exists? #=> true
|
19
17
|
```
|
20
18
|
|
21
|
-
[keep_files]: /lib/shrine/plugins/keep_files.rb
|
22
|
-
[event store]: http://docs.geteventstore.com/introduction/event-sourcing-basics/
|
19
|
+
[keep_files]: https://github.com/shrinerb/shrine/blob/master/lib/shrine/plugins/keep_files.rb
|
@@ -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
|