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,4 +1,6 @@
1
- # Determine MIME Type
1
+ ---
2
+ title: Determine MIME Type
3
+ ---
2
4
 
3
5
  The [`determine_mime_type`][determine_mime_type] plugin allows you to determine
4
6
  and store the actual MIME type of the file analyzed from file content.
@@ -125,7 +127,7 @@ Or disable logging altogether:
125
127
  plugin :determine_mime_type, log_subscriber: nil
126
128
  ```
127
129
 
128
- [determine_mime_type]: /lib/shrine/plugins/determine_mime_type.rb
130
+ [determine_mime_type]: https://github.com/shrinerb/shrine/blob/master/lib/shrine/plugins/determine_mime_type.rb
129
131
  [file]: http://linux.die.net/man/1/file
130
132
  [Windows equivalent]: http://gnuwin32.sourceforge.net/packages/file.htm
131
133
  [ruby-filemagic]: https://github.com/blackwinter/ruby-filemagic
@@ -1,15 +1,19 @@
1
- # Download Endpoint
1
+ ---
2
+ title: Download Endpoint
3
+ ---
2
4
 
3
5
  The [`download_endpoint`][download_endpoint] plugin provides a Rack app for
4
6
  downloading uploaded files from specified storages. This can be useful when
5
7
  files from your storage isn't accessible over URL (e.g. database storages) or
6
8
  if you want to authenticate your downloads.
7
9
 
10
+ ## Global Endpoint
11
+
8
12
  You can configure the plugin with the path prefix which the endpoint will be
9
13
  mounted on.
10
14
 
11
15
  ```rb
12
- plugin :download_endpoint, prefix: "attachments"
16
+ Shrine.plugin :download_endpoint, prefix: "attachments"
13
17
  ```
14
18
 
15
19
  The plugin adds a `Shrine.download_endpoint` method which returns a Rack
@@ -30,6 +34,62 @@ Links to the download endpoint are generated by calling
30
34
  ```rb
31
35
  uploaded_file.download_url #=> "/attachments/eyJpZCI6ImFkdzlyeTM..."
32
36
  ```
37
+ ## Endpoint via Uploader
38
+
39
+ You can also configure the plugin in the uploader directly - just make sure to mount it via your Uploader-class.
40
+
41
+ ```rb
42
+ class ImageUploader < Shrine
43
+ plugin :download_endpoint, prefix: "images"
44
+ end
45
+ ```
46
+
47
+ ```rb
48
+ # config/routes.rb (Rails)
49
+ Rails.application.routes.draw do
50
+ # ...
51
+ mount ImageUploader.download_endpoint => "/images"
52
+ end
53
+ ```
54
+
55
+ *Hint: For shrine versions 2.x -> ensure that you don't include the plugin
56
+ twice (globally and in your uploader class - see #408)*
57
+
58
+ ## Calling from a controller
59
+
60
+ If you want to run additional code around the download (such as authentication),
61
+ mounting the download endpoint in your router might be limiting. You can instead
62
+ create a custom controller action and handle download requests there using
63
+ `Shrine.download_response`:
64
+
65
+ ```rb
66
+ # config/routes.rb (Rails)
67
+ Rails.application.routes.draw do
68
+ # ...
69
+ get "/attachments/*rest", to: "downloads#image"
70
+ end
71
+ ```
72
+ ```rb
73
+ # app/controllers/downloads_controller.rb (Rails)
74
+ class DownloadsController < ApplicationController
75
+ def image
76
+ # ... we can perform authentication here ...
77
+ set_rack_response ImageUploader.download_response(request.env)
78
+ end
79
+
80
+ private
81
+
82
+ def set_rack_response((status, headers, body))
83
+ self.status = status
84
+ self.headers.merge!(headers)
85
+ self.response_body = body
86
+ end
87
+ end
88
+ ```
89
+
90
+ If you want to create an endpoint with a custom path, you can use the
91
+ [`rack_response`][rack_response] plugin directly, which this plugin uses
92
+ internally.
33
93
 
34
94
  ## Host
35
95
 
@@ -99,11 +159,6 @@ You can override any of the options above when creating the endpoint:
99
159
  Shrine.download_endpoint(disposition: "attachment")
100
160
  ```
101
161
 
102
- ## Custom endpoint
103
-
104
- If you want to have more control on download requests, you can use the
105
- `rack_response` plugin which this plugin uses internally.
106
-
107
162
  ## Plugin options
108
163
 
109
164
  | Name | Description | Default |
@@ -114,4 +169,5 @@ If you want to have more control on download requests, you can use the
114
169
  | `:prefix` | Path prefix prepended to download URLs | `nil` |
115
170
  | `:redirect` | Whether to redirect to uploaded files on the storage | `false` |
116
171
 
117
- [download_endpoint]: /lib/shrine/plugins/download_endpoint.rb
172
+ [download_endpoint]: https://github.com/shrinerb/shrine/blob/master/lib/shrine/plugins/download_endpoint.rb
173
+ [rack_response]: https://shrinerb.com/docs/plugins/rack_response
@@ -1,4 +1,6 @@
1
- # Dynamic Storage
1
+ ---
2
+ title: Dynamic Storage
3
+ ---
2
4
 
3
5
  The [`dynamic_storage`][dynamic_storage] plugin allows you to register a
4
6
  storage using a regex, and evaluate the storage class dynamically depending on
@@ -10,7 +12,7 @@ Example:
10
12
  plugin :dynamic_storage
11
13
 
12
14
  storage /store_(\w+)/ do |match|
13
- Shrine::Storages::S3.new(bucket: match[1])
15
+ Shrine::Storage::S3.new(bucket: match[1])
14
16
  end
15
17
  ```
16
18
 
@@ -20,4 +22,4 @@ the bucket "foo". The block is yielded an instance of `MatchData`.
20
22
 
21
23
  This can be useful in combination with the `default_storage` plugin.
22
24
 
23
- [dynamic_storage]: /lib/shrine/plugins/dynamic_storage.rb
25
+ [dynamic_storage]: https://github.com/shrinerb/shrine/blob/master/lib/shrine/plugins/dynamic_storage.rb
@@ -0,0 +1,263 @@
1
+ ---
2
+ title: Entity
3
+ ---
4
+
5
+ The [`entity`][entity] plugin provides integration for handling attachments on
6
+ immutable structs. It is built on top of the [`column`][column] plugin.
7
+
8
+ ```rb
9
+ plugin :entity
10
+ ```
11
+
12
+ ## Attachment
13
+
14
+ Including a `Shrine::Attachment` module into an entity class will add the
15
+ following instance methods:
16
+
17
+ * `#<name>` – returns the attached file
18
+ * `#<name>_url` – returns the attached file URL
19
+ * `#<name>_attacher` – returns a `Shrine::Attacher` instance
20
+
21
+ These methods read attachment data from the `#<name>_data` attribute on the
22
+ entity instance.
23
+
24
+ ```rb
25
+ class Photo
26
+ attr_reader :image_data
27
+
28
+ include ImageUploader::Attachment(:image)
29
+ end
30
+ ```
31
+ ```rb
32
+ photo = Photo.new(image_data: '{"id":"...","storage":"...","metadata":{...}}')
33
+ photo.image #=> #<ImageUploader::UploadedFile>
34
+ photo.image_url #=> "https://example.com/image.jpg"
35
+ photo.image_attacher #=> #<ImageUploader::Attacher>
36
+ ```
37
+
38
+ #### `#<name>`
39
+
40
+ Calls `Attacher#get`, which returns an `UploadedFile` object instantiated from
41
+ attachment data.
42
+
43
+ ```rb
44
+ photo = Photo.new(image_data: '{"id":"foo.jpg","storage":"store","metadata":{...}}')
45
+ photo.image #=> #<ImageUploader::UploadedFile>
46
+ photo.image.id #=> "foo.jpg"
47
+ photo.image.storage_key #=> :store
48
+ photo.image.metadata #=> { ... }
49
+ ```
50
+
51
+ If no file is attached, `nil` is returned.
52
+
53
+ ```rb
54
+ photo = Photo.new(image_data: nil)
55
+ photo.image #=> nil
56
+ ```
57
+
58
+ #### `#<name>_url`
59
+
60
+ Calls `Attacher#url`, which returns the URL to the attached file.
61
+
62
+ ```rb
63
+ photo = Photo.new(image_data: {"id":"foo.jpg","storage":"...","metadata":{...}})
64
+ photo.image_url #=> "https://example.com/foo.jpg"
65
+ ```
66
+
67
+ If no file is attached, `nil` is returned.
68
+
69
+ ```rb
70
+ photo = Photo.new(image_data: nil)
71
+ photo.image_url #=> nil
72
+ ```
73
+
74
+ #### `#<name>_attacher`
75
+
76
+ Calls `Attacher.from_entity`, which returns an `Attacher` instance backed by
77
+ the entity object.
78
+
79
+ ```rb
80
+ photo = Photo.new
81
+ photo.image_attacher #=> #<ImageUploader::Attacher>
82
+ photo.image_attacher.record #=> #<Photo>
83
+ photo.image_attacher.name #=> :image
84
+ photo.image_attacher.attribute #=> :image_data
85
+ ```
86
+
87
+ Any additional options will be forwarded to `Attacher#initialize`.
88
+
89
+ ```rb
90
+ photo = Photo.new
91
+ attacher = photo.image_attacher(cache: :other_cache)
92
+ attacher.cache_key #=> :other_cache
93
+ ```
94
+
95
+ You can also specify default attacher options when including
96
+ `Shrine::Attachment`:
97
+
98
+ ```rb
99
+ class Photo
100
+ attr_reader :image_data
101
+
102
+ include ImageUploader::Attachment(:image, store: :other_store)
103
+ end
104
+ ```
105
+ ```rb
106
+ photo = Photo.new
107
+ attacher = photo.image_attacher
108
+ attacher.store_key #=> :other_store
109
+ ```
110
+
111
+ You can retrieve an `Attacher` instance from the entity *class* as well. In
112
+ this case it will not be initialized with any entity instance.
113
+
114
+ ```rb
115
+ attacher = Photo.image_attacher
116
+ attacher #=> #<ImageUploader::Attacher>
117
+ attacher.record #=> nil
118
+ attacher.name #=> nil
119
+
120
+ attacher = Photo.image_attacher(store: :other_store)
121
+ attacher.store_key #=> :other_store
122
+ ```
123
+
124
+ ## Attacher
125
+
126
+ You can also use `Shrine::Attacher` directly (with or without the
127
+ `Shrine::Attachment` module):
128
+
129
+ ```rb
130
+ class Photo
131
+ attr_reader :image_data
132
+ end
133
+ ```
134
+ ```rb
135
+ photo = Photo.new(image_data: '{"id":"...","storage":"...","metadata":{...}}')
136
+ attacher = ImageUploader::Attacher.from_entity(photo, :image)
137
+
138
+ attacher.file #=> #<Shrine::UploadedFile id="bc2e13.jpg" storage=:store ...>
139
+
140
+ attacher.attach(file)
141
+ attacher.file #=> #<Shrine::UploadedFile id="397eca.jpg" storage=:store ...>
142
+ attacher.column_values #=> { image_data: '{"id":"397eca.jpg","storage":"store","metadata":{...}}' }
143
+
144
+ photo = Photo.new(attacher.column_values)
145
+ attacher = ImageUploader::Attacher.from_entity(photo, :image)
146
+
147
+ attacher.file #=> #<Shrine::UploadedFile id="397eca.jpg" storage=:store ...>
148
+ ```
149
+
150
+ ### Loading entity
151
+
152
+ The `Attacher.from_entity` method can be used for creating an `Attacher`
153
+ instance backed by an entity object.
154
+
155
+ ```rb
156
+ photo = Photo.new(image_data: '{"id":"...","storage":"...","metadata":{...}}')
157
+ attacher = ImageUploader::Attacher.from_entity(photo, :image)
158
+
159
+ attacher.record #=> #<Photo>
160
+ attacher.name #=> :image
161
+ attacher.attribute #=> :image_data
162
+
163
+ attacher.file #=> #<ImageUploader::UploadedFile>
164
+ ```
165
+
166
+ Any additional options are forwarded to `Attacher#initialize`.
167
+
168
+ ```rb
169
+ attacher = ImageUploader::Attacher.from_entity(photo, :image, cache: :other_cache)
170
+ attacher.cache_key #=> :other_cache
171
+ ```
172
+
173
+ You can also load an entity into an existing attacher with
174
+ `Attacher#load_entity`.
175
+
176
+ ```rb
177
+ photo = Photo.new(image_data: '{"id":"...","storage":"...","metadata":{...}}')
178
+
179
+ attacher.load_entity(photo, :image)
180
+ attacher.record #=> #<Photo>
181
+ attacher.name #=> :image
182
+ attacher.file #=> #<ImageUploader::UploadedFile>
183
+ ```
184
+
185
+ Or just `Attacher#set_entity` if you don't want to load attachment data:
186
+
187
+ ```rb
188
+ photo = Photo.new(image_data: '{"id":"...","storage":"...","metadata":{...}}')
189
+
190
+ attacher.set_entity(photo, :image) # doesn't load attachment data
191
+ attacher.record #=> #<Photo>
192
+ attacher.name #=> :image
193
+ attacher.file #=> nil
194
+ ```
195
+
196
+ ### Reloading
197
+
198
+ The `Attacher#reload` method reloads attached file from the attachment data on
199
+ the entity attribute and resets dirty tracking.
200
+
201
+ ```rb
202
+ photo = Photo.new
203
+
204
+ attacher = ImageUploader::Attacher.from_entity(photo, :image)
205
+ attacher.file #=> nil
206
+
207
+ photo.image_data = '{"id":"...","storage":"...","metadata":{...}}'
208
+
209
+ attacher.file #=> nil
210
+ attacher.reload
211
+ attacher.file #=> #<ImageUploader::UploadedFile>
212
+ ```
213
+
214
+ If you want to reload attachment data while retaining dirty tracking state, use
215
+ `Attacher#read` instead.
216
+
217
+ ### Column values
218
+
219
+ The `Attacher#column_values` method returns a hash with the entity attribute as
220
+ key and current attachment data as value.
221
+
222
+ ```rb
223
+ attacher = ImageUploader::Attacher.from_entity(Photo.new, :image)
224
+ attacher.attach(io)
225
+
226
+ attacher.column_values #=> { :image_data => '{"id":"...","storage":"...","metadata":{...}}' }
227
+ ```
228
+
229
+ The `Attacher#attribute` method returns just the entity attribute from which
230
+ attached file data is read.
231
+
232
+ ```rb
233
+ attacher = ImageUploader::Attacher.from_entity(Photo.new, :image)
234
+ attacher.attribute #=> :image_data
235
+ ```
236
+
237
+ ### Entity data
238
+
239
+ The `Attacher#record` method returns the entity instance from which the
240
+ attacher was loaded.
241
+
242
+ ```rb
243
+ attacher = ImageUploader::Attacher.from_entity(Photo.new, :image)
244
+ attacher.record #=> #<Photo>
245
+ ```
246
+
247
+ The `Attacher#name` method returns the name of the attachment from which the
248
+ attacher was loaded.
249
+
250
+ ```rb
251
+ attacher = ImageUploader::Attacher.from_entity(Photo.new, :image)
252
+ attacher.name #=> :image
253
+ ```
254
+
255
+ ## Serialization
256
+
257
+ By default, attachment data is serialized into JSON using the `JSON` standard
258
+ library. If you want to change how data is serialized, see the
259
+ [`column`][column serializer] plugin docs.
260
+
261
+ [entity]: https://github.com/shrinerb/shrine/blob/master/lib/shrine/plugins/entity.rb
262
+ [column]: https://shrinerb.com/docs/plugins/column
263
+ [column serializer]: https://shrinerb.com/docs/plugins/column#serializer
@@ -0,0 +1,55 @@
1
+ ---
2
+ title: Form Assign
3
+ ---
4
+
5
+ The [`form_assign`][form_assign] plugin allows attaching file from form params
6
+ without a form object.
7
+
8
+ ```rb
9
+ plugin :form_assign
10
+ ```
11
+
12
+ The `Attacher#form_assign` method will detect the file param and assign it to
13
+ the attacher:
14
+
15
+ ```rb
16
+ attacher = photo.image_attacher
17
+ attacher.form_assign({ "image" => file, "title" => "...", "description" => "..." })
18
+ attacher.file #=> #<Shrine::UploadedFile>
19
+ ```
20
+
21
+ It works with `remote_url`, `data_uri`, and `remove_attachment` plugins:
22
+
23
+ ```rb
24
+ # remote_url plugin
25
+ attacher.form_assign({ "image_remote_url" => "https://example.com/..." })
26
+ attacher.file #=> #<Shrine::UploadedFile>
27
+ ```
28
+ ```rb
29
+ # data_uri plugin
30
+ attacher.form_assign({ "image_data_uri" => "data:image/jpeg;base64,..." })
31
+ attacher.file #=> #<Shrine::UploadedFile>
32
+ ```
33
+ ```rb
34
+ # remove_attachment plugin
35
+ attacher.form_assign({ "remove_image" => "1" })
36
+ attacher.file #=> nil
37
+ ```
38
+
39
+ The return value is a hash with form params, with file param replaced with
40
+ cached file data, which can later be assigned again to the record.
41
+
42
+ ```rb
43
+ attacher.form_assign({ "image" => file, "title" => "...", "description" => "..." })
44
+ #=> { :image => '{"id":"...","storage":"...","metadata":"..."}', "title" => "...", "description" => "..." }
45
+ ```
46
+
47
+ You can also have attached file data returned as the `<name>_data` attribute,
48
+ suitable for persisting.
49
+
50
+ ```rb
51
+ attacher.form_assign({ "image" => image, ... }, result: :attributes)
52
+ #=> { :image_data => '{"id":"...","storage":"...","metadata":"..."}', "title" => "...", "description" => "..." }
53
+ ```
54
+
55
+ [form_assign]: https://github.com/shrinerb/shrine/blob/master/lib/shrine/plugins/form_assign.rb
@@ -1,18 +1,41 @@
1
- # Included
1
+ ---
2
+ title: Included
3
+ ---
2
4
 
3
5
  The [`included`][included] plugin allows you to hook up to the `.included` hook
4
- of the attachment module, and call additional methods on the model which
6
+ of the attachment module, and call additional methods on the model that
5
7
  includes it.
6
8
 
7
9
  ```rb
8
- plugin :included do |name|
9
- before_save do
10
- # ...
10
+ class ImageUploader < Shrine
11
+ plugin :included do |name|
12
+ # called when attachment module is included into a model
13
+
14
+ self #=> Photo (the model class)
15
+ name #=> :image
11
16
  end
12
17
  end
13
18
  ```
19
+ ```rb
20
+ class Photo
21
+ include ImageUploader::Attachment(:image) # triggers the included block
22
+ end
23
+ ```
24
+
25
+ For example, you can use it to define additional methods on the model:
14
26
 
15
- If you want to define additional methods on the model, it's recommended to use
16
- the `module_include` plugin instead.
27
+ ```rb
28
+ class ImageUploader < Shrine
29
+ plugin :included do |name|
30
+ define_method(:"#{name}_width") { send(name)&.width }
31
+ define_method(:"#{name}_height") { send(name)&.height }
32
+ end
33
+ end
34
+ ```
35
+ ```rb
36
+ photo = Photo.new(image: file)
37
+ photo.image_width #=> 1200
38
+ photo.image_height #=> 800
39
+ ```
17
40
 
18
- [included]: /lib/shrine/plugins/included.rb
41
+ [included]: https://github.com/shrinerb/shrine/blob/master/lib/shrine/plugins/included.rb
@@ -1,4 +1,6 @@
1
- # Infer Extension
1
+ ---
2
+ title: Infer Extension
3
+ ---
2
4
 
3
5
  The [`infer_extension`][infer_extension] plugin allows deducing the appropriate
4
6
  file extension for the upload location based on the MIME type of the file. This
@@ -9,21 +11,30 @@ extension might not be known.
9
11
  plugin :infer_extension
10
12
  ```
11
13
 
14
+ By default an extension will only be inferred if needed to supply an otherwise
15
+ missing extension. But option `force: true` will normalize even an already
16
+ present extension to the extension inferred from MIME type. This could be used
17
+ to fix incorrect or malicious extensions on user-submitted files.
18
+
19
+ ```rb
20
+ plugin :infer_extension, force: true
21
+ ```
22
+
12
23
  ## Inferrers
13
24
 
14
- By default `MIME::Types` will be used for inferring the extension, but you can
15
- also choose a different inferrer:
25
+ By default, the [mini_mime] gem will be used for inferring the extension, but
26
+ you can also choose a different inferrer:
16
27
 
17
28
  ```rb
18
- plugin :infer_extension, inferrer: :mini_mime
29
+ plugin :infer_extension, inferrer: :mime_types
19
30
  ```
20
31
 
21
32
  The following inferrers are accepted:
22
33
 
23
- | Name | Description |
24
- | :------------ | :----------- |
25
- | `:mime_types` | (Default). Uses the [mime-types] gem to infer the appropriate extension from MIME type. |
26
- | `:mini_mime` | Uses the [mini_mime] gem to infer the appropriate extension from MIME type. |
34
+ | Name | Description |
35
+ | :------------ | :----------- |
36
+ | `:mini_mime` | (Default). Uses the [mini_mime] gem to infer the appropriate extension from MIME type. |
37
+ | `:mime_types` | Uses the [mime-types] gem to infer the appropriate extension from MIME type. |
27
38
 
28
39
  You can also define your own inferrer, with the possibility to call the
29
40
  built-in inferrers:
@@ -31,7 +42,7 @@ built-in inferrers:
31
42
  ```rb
32
43
  plugin :infer_extension, inferrer: -> (mime_type, inferrers) do
33
44
  # don't add extension if the file is a text file
34
- inferrers[:rack_mime].call(mime_type) unless mime_type == "text/plain"
45
+ inferrers[:mini_mime].call(mime_type) unless mime_type == "text/plain"
35
46
  end
36
47
  ```
37
48
 
@@ -89,6 +100,6 @@ Or disable logging altogether:
89
100
  plugin :infer_extension, log_subscriber: nil
90
101
  ```
91
102
 
92
- [infer_extension]: /lib/shrine/plugins/infer_extension.rb
103
+ [infer_extension]: https://github.com/shrinerb/shrine/blob/master/lib/shrine/plugins/infer_extension.rb
93
104
  [mime-types]: https://github.com/mime-types/ruby-mime-types
94
105
  [mini_mime]: https://github.com/discourse/mini_mime
@@ -1,7 +1,9 @@
1
- # Instrumentation
1
+ ---
2
+ title: Instrumentation
3
+ ---
2
4
 
3
- The [`instrumentation`][instrumentation] plugin sends events for various
4
- operations to a centralized notification component. In addition to that it
5
+ The [`instrumentation`][instrumentation] plugin publishes events for various
6
+ operations to a centralized notification component. In addition to that, it
5
7
  provides default logging for these events.
6
8
 
7
9
  ```rb
@@ -40,6 +42,13 @@ Download (1002ms) – {:storage=>:store, :location=>"ed0e30ddec8b97813f2c1f4cfd1
40
42
  Delete (700ms) – {:storage=>:store, :location=>"ed0e30ddec8b97813f2c1f4cfd1700b4", :uploader=>Shrine}
41
43
  ```
42
44
 
45
+ It uses `Shrine.logger` for logging, which allows you to change where and how
46
+ are the logs going to be written:
47
+
48
+ ```rb
49
+ Shrine.logger = Rails.logger # in Rails apps
50
+ ```
51
+
43
52
  You can choose to log only certain events, e.g. we can exclude metadata
44
53
  extraction:
45
54
 
@@ -79,6 +88,7 @@ The following events are instrumented by the `instrumentation` plugin:
79
88
 
80
89
  * [`upload.shrine`](#uploadshrine)
81
90
  * [`download.shrine`](#downloadshrine)
91
+ * [`open.shrine`](#openshrine)
82
92
  * [`exists.shrine`](#existsshrine)
83
93
  * [`delete.shrine`](#deleteshrine)
84
94
  * [`metadata.shrine`](#metadatashrine)
@@ -94,21 +104,33 @@ following payload:
94
104
  | `:location` | The location of the uploaded file |
95
105
  | `:io` | The uploaded IO object |
96
106
  | `:upload_options` | Any upload options that were specified |
97
- | `:options` | Some additional context information |
107
+ | `:metadata` | Metadata extracted during upload |
108
+ | `:options` | Any additional uploader options |
98
109
  | `:uploader` | The uploader class that sent the event |
99
110
 
100
111
  ### download.shrine
101
112
 
102
- The `download.shrine` event is logged on `UploadedFile#open` (which includes
103
- `UploadedFile#download` and `UploadedFile#stream` methods as well), and
104
- contains the following payload:
113
+ The `download.shrine` event is logged on `UploadedFile#stream` (which includes
114
+ `UploadedFile#download`), and contains the following payload:
105
115
 
106
- | Key | Description |
107
- | :-- | :---- |
108
- | `:storage` | The storage identifier |
109
- | `:location` | The location of the uploaded file |
110
- | `:download_options` | Any upload options that were specified |
111
- | `:uploader` | The uploader class that sent the event |
116
+ | Key | Description |
117
+ | :-- | :---- |
118
+ | `:storage` | The storage identifier |
119
+ | `:location` | The location of the uploaded file |
120
+ | `:download_options` | Any download options that were specified |
121
+ | `:uploader` | The uploader class that sent the event |
122
+
123
+ ### open.shrine
124
+
125
+ The `download.shrine` event is logged on `UploadedFile#open` or when uploaded
126
+ file is implicitly opened on calling an IO method.
127
+
128
+ | Key | Description |
129
+ | :-- | :---- |
130
+ | `:storage` | The storage identifier |
131
+ | `:location` | The location of the uploaded file |
132
+ | `:download_options` | Any download options that were specified |
133
+ | `:uploader` | The uploader class that sent the event |
112
134
 
113
135
  ### exists.shrine
114
136
 
@@ -141,7 +163,7 @@ following payload:
141
163
  | :-- | :---- |
142
164
  | `:storage` | The storage identifier |
143
165
  | `:io` | The uploaded IO object |
144
- | `:options` | Some additional context information |
166
+ | `:options` | Any options sent to the uploader |
145
167
  | `:uploader` | The uploader class that sent the event |
146
168
 
147
169
  ## API
@@ -151,7 +173,7 @@ methods:
151
173
 
152
174
  ```rb
153
175
  # sends a `my_event.shrine` event to the notifications component
154
- Shrine.instrument(:my_event, foo: "bar") do
176
+ Shrine.instrument(:my_event, { foo: "bar" }) do
155
177
  # do work
156
178
  end
157
179
  ```
@@ -165,6 +187,6 @@ Shrine.subscribe(:my_event) do |event|
165
187
  end
166
188
  ```
167
189
 
168
- [instrumentation]: /lib/shrine/plugins/instrumentation.rb
190
+ [instrumentation]: https://github.com/shrinerb/shrine/blob/master/lib/shrine/plugins/instrumentation.rb
169
191
  [ActiveSupport::Notifications]: https://api.rubyonrails.org/classes/ActiveSupport/Notifications.html
170
192
  [dry-monitor]: https://github.com/dry-rb/dry-monitor