shrine 2.19.4 → 3.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (209) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +485 -43
  3. data/LICENSE.txt +1 -1
  4. data/README.md +81 -977
  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 +102 -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 +1115 -0
  20. data/doc/metadata.md +190 -109
  21. data/doc/multiple_files.md +62 -34
  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 +162 -101
  34. data/doc/plugins/derivatives.md +829 -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 +14 -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 +185 -167
  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 +4 -0
  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/retrieving_uploads.md +4 -1
  116. data/doc/securing_uploads.md +60 -37
  117. data/doc/storage/file_system.md +20 -3
  118. data/doc/storage/memory.md +19 -0
  119. data/doc/storage/s3.md +117 -83
  120. data/doc/testing.md +124 -144
  121. data/doc/upgrading_to_3.md +710 -0
  122. data/doc/validation.md +54 -90
  123. data/lib/shrine/attacher.rb +287 -171
  124. data/lib/shrine/attachment.rb +13 -46
  125. data/lib/shrine/plugins/_persistence.rb +93 -0
  126. data/lib/shrine/plugins/activerecord.rb +77 -34
  127. data/lib/shrine/plugins/add_metadata.rb +25 -17
  128. data/lib/shrine/plugins/atomic_helpers.rb +119 -0
  129. data/lib/shrine/plugins/backgrounding.rb +77 -113
  130. data/lib/shrine/plugins/cached_attachment_data.rb +6 -15
  131. data/lib/shrine/plugins/column.rb +102 -0
  132. data/lib/shrine/plugins/data_uri.rb +38 -36
  133. data/lib/shrine/plugins/default_storage.rb +45 -15
  134. data/lib/shrine/plugins/default_url.rb +12 -24
  135. data/lib/shrine/plugins/default_url_options.rb +3 -30
  136. data/lib/shrine/plugins/delete_raw.rb +10 -16
  137. data/lib/shrine/plugins/derivation_endpoint.rb +89 -134
  138. data/lib/shrine/plugins/derivatives.rb +637 -0
  139. data/lib/shrine/plugins/determine_mime_type.rb +9 -21
  140. data/lib/shrine/plugins/download_endpoint.rb +109 -133
  141. data/lib/shrine/plugins/dynamic_storage.rb +5 -11
  142. data/lib/shrine/plugins/entity.rb +152 -0
  143. data/lib/shrine/plugins/form_assign.rb +108 -0
  144. data/lib/shrine/plugins/included.rb +6 -6
  145. data/lib/shrine/plugins/infer_extension.rb +13 -20
  146. data/lib/shrine/plugins/instrumentation.rb +54 -42
  147. data/lib/shrine/plugins/keep_files.rb +3 -15
  148. data/lib/shrine/plugins/metadata_attributes.rb +28 -19
  149. data/lib/shrine/plugins/mirroring.rb +142 -0
  150. data/lib/shrine/plugins/model.rb +158 -0
  151. data/lib/shrine/plugins/module_include.rb +3 -3
  152. data/lib/shrine/plugins/multi_cache.rb +27 -0
  153. data/lib/shrine/plugins/presign_endpoint.rb +18 -22
  154. data/lib/shrine/plugins/pretty_location.rb +15 -9
  155. data/lib/shrine/plugins/processing.rb +22 -9
  156. data/lib/shrine/plugins/rack_file.rb +2 -42
  157. data/lib/shrine/plugins/rack_response.rb +15 -10
  158. data/lib/shrine/plugins/recache.rb +6 -5
  159. data/lib/shrine/plugins/refresh_metadata.rb +13 -11
  160. data/lib/shrine/plugins/remote_url.rb +49 -49
  161. data/lib/shrine/plugins/remove_attachment.rb +10 -6
  162. data/lib/shrine/plugins/remove_invalid.rb +19 -8
  163. data/lib/shrine/plugins/restore_cached_data.rb +13 -7
  164. data/lib/shrine/plugins/sequel.rb +86 -36
  165. data/lib/shrine/plugins/signature.rb +10 -16
  166. data/lib/shrine/plugins/store_dimensions.rb +35 -40
  167. data/lib/shrine/plugins/tempfile.rb +1 -3
  168. data/lib/shrine/plugins/type_predicates.rb +113 -0
  169. data/lib/shrine/plugins/upload_endpoint.rb +25 -23
  170. data/lib/shrine/plugins/upload_options.rb +14 -15
  171. data/lib/shrine/plugins/url_options.rb +31 -0
  172. data/lib/shrine/plugins/validation.rb +80 -0
  173. data/lib/shrine/plugins/validation_helpers.rb +34 -57
  174. data/lib/shrine/plugins/versions.rb +107 -87
  175. data/lib/shrine/plugins.rb +22 -0
  176. data/lib/shrine/storage/file_system.rb +46 -64
  177. data/lib/shrine/storage/linter.rb +42 -7
  178. data/lib/shrine/storage/memory.rb +49 -0
  179. data/lib/shrine/storage/s3.rb +154 -158
  180. data/lib/shrine/uploaded_file.rb +28 -30
  181. data/lib/shrine/version.rb +3 -3
  182. data/lib/shrine.rb +86 -149
  183. data/shrine.gemspec +9 -10
  184. metadata +79 -83
  185. data/doc/migrating_storage.md +0 -76
  186. data/doc/plugins/backup.md +0 -31
  187. data/doc/plugins/copy.md +0 -24
  188. data/doc/plugins/delete_promoted.md +0 -12
  189. data/doc/plugins/direct_upload.md +0 -172
  190. data/doc/plugins/hooks.md +0 -58
  191. data/doc/plugins/logging.md +0 -42
  192. data/doc/plugins/migration_helpers.md +0 -60
  193. data/doc/plugins/moving.md +0 -19
  194. data/doc/plugins/multi_delete.md +0 -20
  195. data/doc/plugins/parallelize.md +0 -16
  196. data/doc/plugins/parsed_json.md +0 -23
  197. data/doc/regenerating_versions.md +0 -143
  198. data/lib/shrine/plugins/background_helpers.rb +0 -5
  199. data/lib/shrine/plugins/backup.rb +0 -90
  200. data/lib/shrine/plugins/copy.rb +0 -50
  201. data/lib/shrine/plugins/delete_promoted.rb +0 -20
  202. data/lib/shrine/plugins/direct_upload.rb +0 -217
  203. data/lib/shrine/plugins/hooks.rb +0 -90
  204. data/lib/shrine/plugins/logging.rb +0 -142
  205. data/lib/shrine/plugins/migration_helpers.rb +0 -70
  206. data/lib/shrine/plugins/moving.rb +0 -57
  207. data/lib/shrine/plugins/multi_delete.rb +0 -32
  208. data/lib/shrine/plugins/parallelize.rb +0 -78
  209. data/lib/shrine/plugins/parsed_json.rb +0 -29
@@ -1,22 +1,19 @@
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 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, destroyed: true, replaced: true
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
- # 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