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.
Files changed (211) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +523 -41
  3. data/LICENSE.txt +1 -1
  4. data/README.md +83 -979
  5. data/doc/advantages.md +231 -204
  6. data/doc/attacher.md +304 -153
  7. data/doc/carrierwave.md +297 -226
  8. data/doc/changing_derivatives.md +308 -0
  9. data/doc/changing_location.md +103 -21
  10. data/doc/changing_storage.md +110 -0
  11. data/doc/creating_persistence_plugins.md +132 -0
  12. data/doc/creating_plugins.md +43 -23
  13. data/doc/creating_storages.md +19 -5
  14. data/doc/design.md +147 -97
  15. data/doc/direct_s3.md +38 -28
  16. data/doc/external/articles.md +63 -0
  17. data/doc/external/extensions.md +53 -0
  18. data/doc/external/misc.md +32 -0
  19. data/doc/getting_started.md +1156 -0
  20. data/doc/metadata.md +190 -109
  21. data/doc/multiple_files.md +93 -30
  22. data/doc/paperclip.md +384 -262
  23. data/doc/plugins/activerecord.md +177 -46
  24. data/doc/plugins/add_metadata.md +139 -38
  25. data/doc/plugins/atomic_helpers.md +217 -0
  26. data/doc/plugins/backgrounding.md +156 -98
  27. data/doc/plugins/cached_attachment_data.md +7 -5
  28. data/doc/plugins/column.md +121 -0
  29. data/doc/plugins/data_uri.md +23 -22
  30. data/doc/plugins/default_storage.md +36 -10
  31. data/doc/plugins/default_url.md +30 -13
  32. data/doc/plugins/delete_raw.md +4 -2
  33. data/doc/plugins/derivation_endpoint.md +186 -101
  34. data/doc/plugins/derivatives.md +839 -0
  35. data/doc/plugins/determine_mime_type.md +4 -2
  36. data/doc/plugins/download_endpoint.md +64 -8
  37. data/doc/plugins/dynamic_storage.md +5 -3
  38. data/doc/plugins/entity.md +263 -0
  39. data/doc/plugins/form_assign.md +55 -0
  40. data/doc/plugins/included.md +31 -8
  41. data/doc/plugins/infer_extension.md +21 -10
  42. data/doc/plugins/instrumentation.md +38 -16
  43. data/doc/plugins/keep_files.md +16 -17
  44. data/doc/plugins/metadata_attributes.md +42 -13
  45. data/doc/plugins/mirroring.md +118 -0
  46. data/doc/plugins/model.md +210 -0
  47. data/doc/plugins/module_include.md +4 -2
  48. data/doc/plugins/multi_cache.md +24 -0
  49. data/doc/plugins/persistence.md +101 -0
  50. data/doc/plugins/presign_endpoint.md +9 -4
  51. data/doc/plugins/pretty_location.md +16 -3
  52. data/doc/plugins/processing.md +4 -2
  53. data/doc/plugins/rack_file.md +8 -2
  54. data/doc/plugins/rack_response.md +6 -2
  55. data/doc/plugins/recache.md +4 -2
  56. data/doc/plugins/refresh_metadata.md +49 -9
  57. data/doc/plugins/remote_url.md +84 -47
  58. data/doc/plugins/remove_attachment.md +27 -6
  59. data/doc/plugins/remove_invalid.md +21 -6
  60. data/doc/plugins/restore_cached_data.md +11 -3
  61. data/doc/plugins/sequel.md +159 -35
  62. data/doc/plugins/signature.md +16 -5
  63. data/doc/plugins/store_dimensions.md +14 -2
  64. data/doc/plugins/tempfile.md +4 -2
  65. data/doc/plugins/type_predicates.md +96 -0
  66. data/doc/plugins/upload_endpoint.md +13 -13
  67. data/doc/plugins/upload_options.md +6 -4
  68. data/doc/plugins/{default_url_options.md → url_options.md} +9 -7
  69. data/doc/plugins/validation.md +97 -0
  70. data/doc/plugins/validation_helpers.md +16 -13
  71. data/doc/plugins/versions.md +15 -19
  72. data/doc/processing.md +438 -221
  73. data/doc/refile.md +188 -170
  74. data/doc/release_notes/1.0.0.md +4 -0
  75. data/doc/release_notes/1.1.0.md +6 -2
  76. data/doc/release_notes/1.2.0.md +4 -0
  77. data/doc/release_notes/1.3.0.md +4 -0
  78. data/doc/release_notes/1.4.0.md +4 -0
  79. data/doc/release_notes/1.4.1.md +4 -0
  80. data/doc/release_notes/1.4.2.md +4 -0
  81. data/doc/release_notes/2.0.0.md +4 -0
  82. data/doc/release_notes/2.0.1.md +4 -0
  83. data/doc/release_notes/2.1.0.md +5 -1
  84. data/doc/release_notes/2.1.1.md +4 -0
  85. data/doc/release_notes/2.10.0.md +4 -0
  86. data/doc/release_notes/2.10.1.md +4 -0
  87. data/doc/release_notes/2.11.0.md +4 -0
  88. data/doc/release_notes/2.12.0.md +4 -0
  89. data/doc/release_notes/2.13.0.md +4 -0
  90. data/doc/release_notes/2.14.0.md +5 -1
  91. data/doc/release_notes/2.15.0.md +11 -7
  92. data/doc/release_notes/2.16.0.md +4 -0
  93. data/doc/release_notes/2.17.0.md +4 -0
  94. data/doc/release_notes/2.18.0.md +4 -0
  95. data/doc/release_notes/2.19.0.md +6 -3
  96. data/doc/release_notes/2.2.0.md +4 -0
  97. data/doc/release_notes/2.3.0.md +4 -0
  98. data/doc/release_notes/2.3.1.md +4 -0
  99. data/doc/release_notes/2.4.0.md +4 -0
  100. data/doc/release_notes/2.4.1.md +4 -0
  101. data/doc/release_notes/2.5.0.md +4 -0
  102. data/doc/release_notes/2.6.0.md +4 -0
  103. data/doc/release_notes/2.6.1.md +4 -0
  104. data/doc/release_notes/2.7.0.md +4 -0
  105. data/doc/release_notes/2.8.0.md +4 -0
  106. data/doc/release_notes/2.9.0.md +4 -0
  107. data/doc/release_notes/3.0.0.md +981 -0
  108. data/doc/release_notes/3.0.1.md +22 -0
  109. data/doc/release_notes/3.1.0.md +73 -0
  110. data/doc/release_notes/3.2.0.md +96 -0
  111. data/doc/release_notes/3.2.1.md +31 -0
  112. data/doc/release_notes/3.2.2.md +14 -0
  113. data/doc/release_notes/3.3.0.md +105 -0
  114. data/doc/release_notes/3.4.0.md +35 -0
  115. data/doc/release_notes/3.5.0.md +63 -0
  116. data/doc/release_notes/3.6.0.md +23 -0
  117. data/doc/retrieving_uploads.md +5 -2
  118. data/doc/securing_uploads.md +60 -37
  119. data/doc/storage/file_system.md +20 -3
  120. data/doc/storage/memory.md +19 -0
  121. data/doc/storage/s3.md +122 -78
  122. data/doc/testing.md +141 -133
  123. data/doc/upgrading_to_3.md +708 -0
  124. data/doc/validation.md +54 -90
  125. data/lib/shrine/attacher.rb +292 -169
  126. data/lib/shrine/attachment.rb +13 -46
  127. data/lib/shrine/plugins/_persistence.rb +93 -0
  128. data/lib/shrine/plugins/activerecord.rb +77 -34
  129. data/lib/shrine/plugins/add_metadata.rb +25 -17
  130. data/lib/shrine/plugins/atomic_helpers.rb +119 -0
  131. data/lib/shrine/plugins/backgrounding.rb +77 -113
  132. data/lib/shrine/plugins/cached_attachment_data.rb +6 -15
  133. data/lib/shrine/plugins/column.rb +102 -0
  134. data/lib/shrine/plugins/data_uri.rb +38 -36
  135. data/lib/shrine/plugins/default_storage.rb +45 -15
  136. data/lib/shrine/plugins/default_url.rb +12 -24
  137. data/lib/shrine/plugins/default_url_options.rb +3 -30
  138. data/lib/shrine/plugins/delete_raw.rb +10 -16
  139. data/lib/shrine/plugins/derivation_endpoint.rb +130 -171
  140. data/lib/shrine/plugins/derivatives.rb +645 -0
  141. data/lib/shrine/plugins/determine_mime_type.rb +9 -21
  142. data/lib/shrine/plugins/download_endpoint.rb +118 -133
  143. data/lib/shrine/plugins/dynamic_storage.rb +5 -11
  144. data/lib/shrine/plugins/entity.rb +158 -0
  145. data/lib/shrine/plugins/form_assign.rb +108 -0
  146. data/lib/shrine/plugins/included.rb +6 -6
  147. data/lib/shrine/plugins/infer_extension.rb +17 -20
  148. data/lib/shrine/plugins/instrumentation.rb +59 -43
  149. data/lib/shrine/plugins/keep_files.rb +3 -15
  150. data/lib/shrine/plugins/metadata_attributes.rb +28 -19
  151. data/lib/shrine/plugins/mirroring.rb +142 -0
  152. data/lib/shrine/plugins/model.rb +160 -0
  153. data/lib/shrine/plugins/module_include.rb +3 -3
  154. data/lib/shrine/plugins/multi_cache.rb +27 -0
  155. data/lib/shrine/plugins/presign_endpoint.rb +27 -28
  156. data/lib/shrine/plugins/pretty_location.rb +15 -9
  157. data/lib/shrine/plugins/processing.rb +22 -9
  158. data/lib/shrine/plugins/rack_file.rb +2 -42
  159. data/lib/shrine/plugins/rack_response.rb +21 -10
  160. data/lib/shrine/plugins/recache.rb +6 -5
  161. data/lib/shrine/plugins/refresh_metadata.rb +13 -11
  162. data/lib/shrine/plugins/remote_url.rb +49 -49
  163. data/lib/shrine/plugins/remove_attachment.rb +12 -6
  164. data/lib/shrine/plugins/remove_invalid.rb +19 -8
  165. data/lib/shrine/plugins/restore_cached_data.rb +13 -7
  166. data/lib/shrine/plugins/sequel.rb +86 -36
  167. data/lib/shrine/plugins/signature.rb +10 -16
  168. data/lib/shrine/plugins/store_dimensions.rb +35 -40
  169. data/lib/shrine/plugins/tempfile.rb +1 -3
  170. data/lib/shrine/plugins/type_predicates.rb +113 -0
  171. data/lib/shrine/plugins/upload_endpoint.rb +28 -24
  172. data/lib/shrine/plugins/upload_options.rb +14 -15
  173. data/lib/shrine/plugins/url_options.rb +31 -0
  174. data/lib/shrine/plugins/validation.rb +80 -0
  175. data/lib/shrine/plugins/validation_helpers.rb +35 -58
  176. data/lib/shrine/plugins/versions.rb +107 -87
  177. data/lib/shrine/plugins.rb +22 -0
  178. data/lib/shrine/storage/file_system.rb +46 -64
  179. data/lib/shrine/storage/linter.rb +42 -7
  180. data/lib/shrine/storage/memory.rb +49 -0
  181. data/lib/shrine/storage/s3.rb +173 -160
  182. data/lib/shrine/uploaded_file.rb +32 -32
  183. data/lib/shrine/version.rb +3 -3
  184. data/lib/shrine.rb +87 -150
  185. data/shrine.gemspec +11 -12
  186. metadata +92 -82
  187. data/doc/migrating_storage.md +0 -76
  188. data/doc/plugins/backup.md +0 -31
  189. data/doc/plugins/copy.md +0 -24
  190. data/doc/plugins/delete_promoted.md +0 -12
  191. data/doc/plugins/direct_upload.md +0 -172
  192. data/doc/plugins/hooks.md +0 -58
  193. data/doc/plugins/logging.md +0 -42
  194. data/doc/plugins/migration_helpers.md +0 -60
  195. data/doc/plugins/moving.md +0 -19
  196. data/doc/plugins/multi_delete.md +0 -20
  197. data/doc/plugins/parallelize.md +0 -16
  198. data/doc/plugins/parsed_json.md +0 -23
  199. data/doc/regenerating_versions.md +0 -143
  200. data/lib/shrine/plugins/background_helpers.rb +0 -5
  201. data/lib/shrine/plugins/backup.rb +0 -90
  202. data/lib/shrine/plugins/copy.rb +0 -50
  203. data/lib/shrine/plugins/delete_promoted.rb +0 -20
  204. data/lib/shrine/plugins/direct_upload.rb +0 -217
  205. data/lib/shrine/plugins/hooks.rb +0 -90
  206. data/lib/shrine/plugins/logging.rb +0 -142
  207. data/lib/shrine/plugins/migration_helpers.rb +0 -70
  208. data/lib/shrine/plugins/moving.rb +0 -57
  209. data/lib/shrine/plugins/multi_delete.rb +0 -32
  210. data/lib/shrine/plugins/parallelize.rb +0 -78
  211. data/lib/shrine/plugins/parsed_json.rb +0 -29
@@ -1,22 +1,21 @@
1
- # Keep Files
1
+ ---
2
+ title: Keep Files
3
+ ---
2
4
 
3
- The [`keep_files`][keep_files] plugin gives you the ability to prevent files
4
- from being deleted. This functionality is useful when implementing soft
5
- deletes, or when implementing some kind of [event store] where you need to
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 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, destroyed: true, replaced: true
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
- [event store]: http://docs.geteventstore.com/introduction/event-sourcing-basics/
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
- # Metadata Attributes
1
+ ---
2
+ title: Metadata Attributes
3
+ ---
2
4
 
3
- The [`metadata_attributes`][metadata_attributes] plugin allows you to sync
4
- attachment metadata to additional record attributes. You can provide a hash of
5
- mappings to the plugin call itself or the `Attacher.metadata_attributes`
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 sync `size` metadata field to `<attachment>_size`
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
- If any corresponding metadata attribute doesn't exist on the record, that
44
- metadata sync will be silently skipped.
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
- # Module Include
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
- # Presign Endpoint
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
- post "/images/presign", to: "presigns#image"
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
- # Pretty Location
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/:version-:uid.:extension
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
@@ -1,4 +1,6 @@
1
- # Processing
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