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,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