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
- # Rack File
1
+ ---
2
+ title: Rack File
3
+ ---
2
4
 
3
5
  The [`rack_file`][rack_file] plugin enables uploaders to accept Rack uploaded
4
6
  file hashes for uploading.
@@ -7,6 +9,8 @@ file hashes for uploading.
7
9
  plugin :rack_file
8
10
  ```
9
11
 
12
+ ## Usage
13
+
10
14
  When a file is uploaded to your Rack application using the
11
15
  `multipart/form-data` parameter encoding, Rack converts the uploaded file to a
12
16
  hash.
@@ -33,6 +37,8 @@ user.avatar = file_hash
33
37
  attacher.assign(file_hash)
34
38
  ```
35
39
 
40
+ ## API
41
+
36
42
  Internally the Rack uploaded file hash will be converted into an IO object
37
43
  using `Shrine.rack_file`, which you can also use directly:
38
44
 
@@ -48,4 +54,4 @@ Note that this plugin is not needed in Rails applications, as Rails already
48
54
  wraps the Rack uploaded file hash into an `ActionDispatch::Http::UploadedFile`
49
55
  object.
50
56
 
51
- [rack_file]: /lib/shrine/plugins/rack_file.rb
57
+ [rack_file]: https://github.com/shrinerb/shrine/blob/master/lib/shrine/plugins/rack_file.rb
@@ -1,4 +1,6 @@
1
- # Rack Response
1
+ ---
2
+ title: Rack Response
3
+ ---
2
4
 
3
5
  The [`rack_response`][rack_response] plugin allows you to convert an
4
6
  `UploadedFile` object into a triple consisting of status, headers, and body,
@@ -8,6 +10,8 @@ suitable for returning as a response in a Rack-based application.
8
10
  plugin :rack_response
9
11
  ```
10
12
 
13
+ ## Usage
14
+
11
15
  To convert a `Shrine::UploadedFile` into a Rack response, simply call
12
16
  `#to_rack_response`:
13
17
 
@@ -107,6 +111,6 @@ uploaded_file.open(
107
111
  uploaded_file.to_rack_response
108
112
  ```
109
113
 
110
- [rack_response]: /lib/shrine/plugins/rack_response.rb
114
+ [rack_response]: https://github.com/shrinerb/shrine/blob/master/lib/shrine/plugins/rack_response.rb
111
115
  [range requests]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Range_requests
112
116
  [Rack::Sendfile]: https://www.rubydoc.info/github/rack/rack/Rack/Sendfile
@@ -1,4 +1,6 @@
1
- # Re-cache
1
+ ---
2
+ title: Re-cache
3
+ ---
2
4
 
3
5
  The [`recache`][recache] plugin allows you to process your attachment after
4
6
  validations succeed, but before the attachment is promoted. This is useful for
@@ -26,4 +28,4 @@ you're using the attacher directly, you can call it manually:
26
28
  attacher.recache if attacher.changed?
27
29
  ```
28
30
 
29
- [recache]: /lib/shrine/plugins/recache.rb
31
+ [recache]: https://github.com/shrinerb/shrine/blob/master/lib/shrine/plugins/recache.rb
@@ -1,4 +1,6 @@
1
- # Refresh Metadata
1
+ ---
2
+ title: Refresh Metadata
3
+ ---
2
4
 
3
5
  The [`refresh_metadata`][refresh_metadata] plugin allows you to re-extract
4
6
  metadata from an uploaded file.
@@ -7,27 +9,65 @@ metadata from an uploaded file.
7
9
  plugin :refresh_metadata
8
10
  ```
9
11
 
10
- It provides `UploadedFile#refresh_metadata!` method, which triggers metadata
11
- extraction (calls `Shrine#extract_metadata`) with the uploaded file opened for
12
- reading, and updates the existing metadata hash with the results.
12
+ It provides `#refresh_metadata!` method, which triggers metadata extraction
13
+ (calls `Shrine#extract_metadata`) with the uploaded file opened for reading,
14
+ and updates the existing metadata hash with the results. This can be done
15
+ on the `Shrine::Attacher` or the `Shrine::UploadedFile` level.
16
+
17
+ ## Attacher
18
+
19
+ Calling `#refresh_metadata!` on a `Shrine::Attacher` object will re-extract
20
+ metadata of the attached file, and when used with a [model], it will write new
21
+ file data back into the attachment attribute.
22
+
23
+ ```rb
24
+ attacher.refresh_metadata!
25
+ attacher.file.metadata # re-extracted metadata
26
+ attacher.record.file_data #=> '{ ... data with updated metadata ... }'
27
+ ```
28
+
29
+ The `Attacher#context` hash will be forwarded to metadata extraction, as well
30
+ as any options that you pass in.
31
+
32
+ ```rb
33
+ # via context
34
+ attacher.context[:foo] = "bar"
35
+ attacher.refresh_metadata! # passes `{ foo: "bar" }` options to metadata extraction
36
+
37
+ # via arguments
38
+ attacher.refresh_metadata!(foo: "bar") # passes `{ foo: "bar" }` options to metadata extraction
39
+ ```
40
+
41
+ ## Uploaded File
42
+
43
+ The `#refresh_metadata!` method can be called on a `Shrine::UploadedFile` object
44
+ as well.
13
45
 
14
46
  ```rb
15
47
  uploaded_file.refresh_metadata!
16
48
  uploaded_file.metadata # re-extracted metadata
17
49
  ```
18
50
 
19
- For remote storages this will make an HTTP request to open the file for
20
- reading, but only the portion of the file needed for extracting each metadata
21
- value will be downloaded.
51
+ If the uploaded file is not open, it is opened before and closed after metadata
52
+ extraction. For remote storage services this will make an HTTP request.
53
+ However, only the portion of the file needed for extracting metadata will be
54
+ downloaded.
22
55
 
23
56
  If the uploaded file is already open, it is passed to metadata extraction as
24
57
  is.
25
58
 
26
59
  ```rb
27
60
  uploaded_file.open do
28
- uploaded_file.refresh_metadata!
61
+ uploaded_file.refresh_metadata! # uses the already opened file
29
62
  # ...
30
63
  end
31
64
  ```
32
65
 
33
- [refresh_metadata]: /lib/shrine/plugins/refresh_metadata.rb
66
+ Any options passed in will be forwarded to metadata extraction:
67
+
68
+ ```rb
69
+ uploaded_file.refresh_metadata!(foo: "bar") # passes `{ foo: "bar" }` options to metadata extraction
70
+ ```
71
+
72
+ [refresh_metadata]: https://github.com/shrinerb/shrine/blob/master/lib/shrine/plugins/refresh_metadata.rb
73
+ [model]: https://shrinerb.com/docs/plugins/model
@@ -1,4 +1,6 @@
1
- # Remote URL
1
+ ---
2
+ title: Remote URL
3
+ ---
2
4
 
3
5
  The [`remote_url`][remote_url] plugin allows you to attach files from a remote
4
6
  location.
@@ -7,82 +9,117 @@ location.
7
9
  plugin :remote_url, max_size: 20*1024*1024
8
10
  ```
9
11
 
10
- If for example your attachment is called "avatar", this plugin will add
11
- `#avatar_remote_url` and `#avatar_remote_url=` methods to your model.
12
+ ## Usage
12
13
 
13
- ```rb
14
- user.avatar #=> nil
15
- user.avatar_remote_url = "http://example.com/cool-image.png"
16
- user.avatar #=> #<Shrine::UploadedFile>
14
+ The plugin will add the `#<name>_remote_url` writer to your model, which
15
+ downloads the remote file and uploads it to temporary storage.
17
16
 
18
- user.avatar.mime_type #=> "image/png"
19
- user.avatar.size #=> 43423
20
- user.avatar.original_filename #=> "cool-image.png"
17
+ ```rb
18
+ photo.image_remote_url = "http://example.com/cool-image.png"
19
+ photo.image.mime_type #=> "image/png"
20
+ photo.image.size #=> 43423
21
+ photo.image.original_filename #=> "cool-image.png"
21
22
  ```
22
23
 
23
- You can also use `#remote_url=` and `#remote_url` methods directly on the
24
- `Shrine::Attacher`:
24
+ If you're using `Shrine::Attacher` directly, you can use
25
+ `Attacher#assign_remote_url`:
25
26
 
26
27
  ```rb
27
- attacher.remote_url = "http://example.com/cool-image.png"
28
+ attacher.assign_remote_url("http://example.com/cool-image.png")
29
+ attacher.file.mime_type #=> "image/png"
30
+ attacher.file.size #=> 43423
31
+ attacher.file.original_filename #=> "cool-image.png"
28
32
  ```
29
33
 
34
+ ## Downloader
35
+
30
36
  By default, the file will be downloaded using `Down.download` from the [Down]
31
- gem. This will use the `Down::NetHttp` backend by default, which is a wrapper
37
+ gem. This will use the [Down::NetHttp] backend by default, which is a wrapper
32
38
  around [open-uri].
33
39
 
34
- ## Dynamic options
40
+ You can pass options to the downloader via the `:downloader` option:
35
41
 
36
- You can dynamically pass options to the downloader by using
37
- `Attacher#assign_remote_url`:
42
+ ```rb
43
+ attacher.assign_remote_url url, downloader: {
44
+ headers: { "Authorization" => "Basic ..." },
45
+ read_timeout: 30, open_timeout: 30,
46
+ max_redirects: 5,
47
+ # ...
48
+ }
49
+ ```
50
+
51
+ You can also change the downloader:
38
52
 
39
53
  ```rb
40
- attacher.assign_remote_url(url, downloader: { 'Authorization' => 'Basic ...' })
54
+ # Gemfile
55
+ gem "http"
56
+ ```
57
+ ```rb
58
+ require "down/http"
59
+
60
+ plugin :remote_url, downloader: -> (url, **options) {
61
+ Down::Http.download(url, **options) do |client|
62
+ client.follow(max_hops: 2).timeout(connect: 2, read: 2)
63
+ end
64
+ }
41
65
  ```
42
66
 
43
- You can also pass any other `Shrine#upload` options:
67
+ Any `Down::NotFound` and `Down::TooLarge` exceptions will be rescued and
68
+ converted into validation errors. If you want to convert any other exceptions
69
+ into validation errors, you can raise them as
70
+ `Shrine::Plugins::RemoteUrl::DownloadError`:
44
71
 
45
72
  ```rb
46
- attacher.assign_remote_url(url, metadata: { "mime_type" => "text/plain" })
73
+ plugin :remote_url, downloader: -> (url, **options) {
74
+ begin
75
+ RestClient.get(url)
76
+ rescue RestClient::ExceptionWithResponse => error
77
+ raise Shrine::Plugins::RemoteUrl::DownloadError, "remote file not found"
78
+ end
79
+ }
47
80
  ```
48
81
 
49
- ## Maximum size
82
+ ### Calling downloader
50
83
 
51
- It's a good practice to limit the maximum filesize of the remote file:
84
+ You can call the downloader directly with `Shrine.remote_url`:
52
85
 
53
86
  ```rb
54
- plugin :remote_url, max_size: 20*1024*1024 # 20 MB
87
+ # or YourUploader.remote_url(...)
88
+ file = Shrine.remote_url("https://example.com/image.jpg")
89
+ file #=> #<Tempfile:...>
55
90
  ```
56
91
 
57
- Now if a file that is bigger than 20MB is assigned, download will be terminated
58
- as soon as it gets the "Content-Length" header, or the size of currently
59
- downloaded content surpasses the maximum size. However, if for whatever reason
60
- you don't want to limit the maximum file size, you can set `:max_size` to nil:
92
+ You can pass additional options as well:
61
93
 
62
94
  ```rb
63
- plugin :remote_url, max_size: nil
95
+ # or YourUploader.remote_url(...)
96
+ Shrine.remote_url("https://example.com/image.jpg", headers: { "Cookie" => "..." })
64
97
  ```
65
98
 
66
- ## Custom downloader
99
+ ## Uploader options
67
100
 
68
- If you want to customize how the file is downloaded, you can override the
69
- `:downloader` parameter and provide your own implementation. For example, you
70
- can use the [http.rb] Down backend for downloading:
101
+ Any additional options passed to `Attacher#assign_remote_url` will be forwarded
102
+ to `Attacher#assign` (and `Shrine#upload`):
71
103
 
72
104
  ```rb
73
- # Gemfile
74
- gem "http"
105
+ attacher.assign_remote_url(url, metadata: { "mime_type" => "text/plain" })
75
106
  ```
107
+
108
+ ## Maximum size
109
+
110
+ It's a good practice to limit the maximum filesize of the remote file:
111
+
76
112
  ```rb
77
- require "down/http"
113
+ plugin :remote_url, max_size: 20*1024*1024 # 20 MB
114
+ ```
78
115
 
79
- down = Down::Http.new do |client|
80
- client
81
- .follow(max_hops: 2)
82
- .timeout(connect: 2, read: 2)
83
- end
116
+ Now if a file that is bigger than 20MB is assigned, download will be terminated
117
+ as soon as it gets the "Content-Length" header, or the size of currently
118
+ downloaded content surpasses the maximum size. However, if for whatever reason
119
+ you don't want to limit the maximum file size, you can set `:max_size` to nil:
84
120
 
85
- plugin :remote_url, max_size: 20*1024*1024, downloader: down.method(:download)
121
+ ```rb
122
+ plugin :remote_url, max_size: nil
86
123
  ```
87
124
 
88
125
  ## Errors
@@ -103,11 +140,10 @@ file ID, and pair that with the `backgrounding` plugin.
103
140
 
104
141
  ## File extension
105
142
 
106
- When attaching from a remote URL, the uploaded file location will have the
107
- extension inferred from the URL. However, some URLs might not have an
108
- extension, in which case the uploaded file location also won't have the
109
- extension. If you want the upload location to always have an extension, you can
110
- load the `infer_extension` plugin to infer it from the MIME type.
143
+ When attaching from a remote URL, the uploaded file location will inherit the
144
+ extension from the URL. However, some URLs might not have an extension. To
145
+ handle this case, you can use the `infer_extension` plugin to infer the
146
+ extension from the MIME type.
111
147
 
112
148
  ```rb
113
149
  plugin :infer_extension
@@ -156,8 +192,9 @@ Or disable logging altogether:
156
192
  plugin :remote_url, log_subscriber: nil
157
193
  ```
158
194
 
159
- [remote_url]: /lib/shrine/plugins/remote_url.rb
195
+ [remote_url]: https://github.com/shrinerb/shrine/blob/master/lib/shrine/plugins/remote_url.rb
160
196
  [Down]: https://github.com/janko/down
197
+ [Down::NetHttp]: https://github.com/janko/down#downnethttp
161
198
  [open-uri]: https://ruby-doc.org/stdlib/libdoc/open-uri/rdoc/OpenURI.html
162
199
  [http.rb]: https://github.com/httprb/http
163
200
  [shrine-url]: https://github.com/shrinerb/shrine-url
@@ -1,4 +1,6 @@
1
- # Remove Attachment
1
+ ---
2
+ title: Remove Attachment
3
+ ---
2
4
 
3
5
  The [`remove_attachment`][remove_attachment] plugin allows you to delete
4
6
  attachments through checkboxes on the web form.
@@ -7,12 +9,31 @@ attachments through checkboxes on the web form.
7
9
  plugin :remove_attachment
8
10
  ```
9
11
 
10
- If for example your attachment is called "avatar", this plugin will add
11
- `#remove_avatar` and `#remove_avatar=` methods to your model. This allows you
12
- to add a form field for removing attachments:
12
+ The plugin adds the `#remove_<name>` accessor to your model, which removes the
13
+ attached file if it receives a truthy value:
13
14
 
14
15
  ```rb
15
- form.check_box :remove_avatar
16
+ photo.image #=> #<Shrine::UploadedFile>
17
+ photo.remove_image = 'true'
18
+ photo.image #=> nil
16
19
  ```
17
20
 
18
- [remove_attachment]: /lib/shrine/plugins/remove_attachment.rb
21
+ This allows you to add a checkbox form field for removing attachments:
22
+
23
+ ```rb
24
+ form_for photo do |f|
25
+ # ...
26
+ f.check_box :remove_image
27
+ end
28
+ ```
29
+
30
+ If you're using the `Shrine::Attacher` directly, you can use the
31
+ `Attacher#remove` accessor:
32
+
33
+ ```rb
34
+ attacher.file #=> #<Shrine::UploadedFile>
35
+ attacher.remove = '1'
36
+ attacher.file #=> nil
37
+ ```
38
+
39
+ [remove_attachment]: https://github.com/shrinerb/shrine/blob/master/lib/shrine/plugins/remove_attachment.rb
@@ -1,12 +1,27 @@
1
- # Remove Invalid
1
+ ---
2
+ title: Remove Invalid
3
+ ---
2
4
 
3
- The [`remove_invalid`][remove_invalid] plugin automatically deletes a new
4
- assigned file if it was invalid and deassigns it from the record. If there was
5
- a previous file attached, it will be assigned back, otherwise no attachment
6
- will be assigned.
5
+ The [`remove_invalid`][remove_invalid] plugin automatically deletes and
6
+ deassigns a new assigned file if it was invalid. If there was a previous file
7
+ attached, it will be assigned back.
7
8
 
8
9
  ```rb
9
10
  plugin :remove_invalid
10
11
  ```
11
12
 
12
- [remove_invalid]: /lib/shrine/plugins/remove_invalid.rb
13
+ ```rb
14
+ # without previous file
15
+ photo.image #=> nil
16
+ photo.image = file # validation fails, assignment is reverted
17
+ photo.valid? #=> false
18
+ photo.image #=> nil
19
+
20
+ # with previous file
21
+ photo.image #=> #<Shrine::UploadedFile id="foo" ...>
22
+ photo.image = file # validation fails, assignment is reverted
23
+ photo.valid? #=> false
24
+ photo.image #=> #<Shrine::UploadedFile id="foo" ...>
25
+ ```
26
+
27
+ [remove_invalid]: https://github.com/shrinerb/shrine/blob/master/lib/shrine/plugins/remove_invalid.rb
@@ -1,4 +1,6 @@
1
- # Restore Cached Data
1
+ ---
2
+ title: Restore Cached Data
3
+ ---
2
4
 
3
5
  The [`restore_cached_data`][restore_cached_data] plugin re-extracts metadata
4
6
  when assigning already cached files, i.e. when the attachment has been retained
@@ -10,7 +12,13 @@ extracted on the client side.
10
12
  ```rb
11
13
  plugin :restore_cached_data
12
14
  ```
15
+ ```rb
16
+ photo.image = { "id" => "path/to/image.jpg", "storage" => "cache", "metadata" => {} }
17
+ photo.image.metadata #=> { "size" => 4823763, "mime_type" => "image/jpeg", ... }
18
+ ```
13
19
 
14
- It uses the `refresh_metadata` plugin to re-extract metadata.
20
+ It uses the [`refresh_metadata`][refresh_metadata] plugin to re-extract
21
+ metadata.
15
22
 
16
- [restore_cached_data]: /lib/shrine/plugins/restore_cached_data.rb
23
+ [restore_cached_data]: https://github.com/shrinerb/shrine/blob/master/lib/shrine/plugins/restore_cached_data.rb
24
+ [refresh_metadata]: https://shrinerb.com/docs/plugins/refresh_metadata
@@ -1,67 +1,191 @@
1
- # Sequel
1
+ ---
2
+ title: Sequel
3
+ ---
2
4
 
3
- The [`sequel`][sequel] plugin extends the "attachment" interface with support
4
- for Sequel.
5
+ The [`sequel`][sequel] plugin adds [Sequel] integration to the attachment
6
+ interface. It is built on top of the [`model`][model] plugin.
5
7
 
6
8
  ```rb
7
- plugin :sequel
9
+ Shrine.plugin :sequel
8
10
  ```
9
11
 
10
- ## Callbacks
12
+ ## Attachment
11
13
 
12
- Now the attachment module will add additional callbacks to the model:
14
+ Including a `Shrine::Attachment` module into a `Sequel::Model` subclass will:
13
15
 
14
- * "before save" Used by the `recache` plugin.
15
- * "after commit" (save) Promotes the attachment, deletes replaced ones.
16
- * "after commit" (destroy) – Deletes the attachment.
16
+ * add [model] attachment methods
17
+ * add [validations](#validations) and [hooks](#hooks) to tie attachment process
18
+ to the record lifecycle
17
19
 
18
- If you want to put promoting/deleting into a background job, see the
19
- `backgrounding` plugin.
20
+ ```rb
21
+ class Photo < Sequel::Model # has `image_data` column
22
+ include ImageUploader::Attachment(:image) # adds methods, callbacks & validations
23
+ end
24
+ ```
25
+ ```rb
26
+ photo = Photo.new
27
+
28
+ photo.image = file # cache attachment
29
+
30
+ photo.image #=> #<Shrine::UploadedFile id="bc2e13.jpg" storage=:cache ...>
31
+ photo.image_data #=> '{"id":"bc2e13.jpg","storage":"cache","metadata":{...}}'
32
+
33
+ photo.save # persist, promote attachment, then persist again
34
+
35
+ photo.image #=> #<Shrine::UploadedFile id="397eca.jpg" storage=:store ...>
36
+ photo.image_data #=> '{"id":"397eca.jpg","storage":"store","metadata":{...}}'
20
37
 
21
- Since attaching first saves the record with a cached attachment, then saves
22
- again with a stored attachment, you can detect this in callbacks:
38
+ photo.destroy # delete attachment
39
+
40
+ photo.image.exists? #=> false
41
+ ```
42
+
43
+ ### Hooks
44
+
45
+ #### After Save
46
+
47
+ After a record is saved and the transaction is committed, `Attacher#finalize`
48
+ is called, which promotes cached file to permanent storage and deletes previous
49
+ file if any.
23
50
 
24
51
  ```rb
25
- class User < Sequel::Model
26
- include ImageUploader::Attachment.new(:avatar)
52
+ photo = Photo.new
27
53
 
28
- def before_save
29
- super
54
+ photo.image = file
55
+ photo.image.storage_key #=> :cache
30
56
 
31
- if changed_columns.include?(:avatar) && avatar_attacher.cached?
32
- # cached
33
- elsif changed_columns.include?(:avatar) && avatar_attacher.stored?
34
- # promoted
35
- end
57
+ photo.save
58
+ photo.image.storage_key #=> :store
59
+ ```
60
+
61
+ #### After Destroy
62
+
63
+ After a record is destroyed and the transaction is committed,
64
+ `Attacher#destroy_attached` method is called, which deletes stored attached
65
+ file if any.
66
+
67
+ ```rb
68
+ photo = Photo.find(photo_id)
69
+ photo.image #=> #<Shrine::UploadedFile>
70
+ photo.image.exists? #=> true
71
+
72
+ photo.destroy
73
+ photo.image.exists? #=> false
74
+ ```
75
+
76
+ #### Overriding hooks
77
+
78
+ You can override any of the following attacher methods to modify callback
79
+ behaviour:
80
+
81
+ * `Attacher#sequel_before_save`
82
+ * `Attacher#sequel_after_save`
83
+ * `Attacher#sequel_after_destroy`
84
+
85
+ ```rb
86
+ class Shrine::Attacher
87
+ def sequel_after_save
88
+ super
89
+ # ...
36
90
  end
37
91
  end
38
92
  ```
39
93
 
40
- If you don't want the attachment module to add any callbacks to the model, and
41
- would instead prefer to call these actions manually, you can disable callbacks:
94
+ #### Skipping Hooks
95
+
96
+ If you don't want the attachment module to add any hooks to your model, you can
97
+ set `:hooks` to `false`:
98
+
99
+ ```rb
100
+ plugin :sequel, hooks: false
101
+ ```
102
+
103
+ ### Validations
104
+
105
+ If you're using the [`validation`][validation] plugin, the attachment module
106
+ will automatically merge attacher errors with model errors.
42
107
 
43
108
  ```rb
44
- plugin :sequel, callbacks: false
109
+ class ImageUploader < Shrine
110
+ plugin :validation_helpers
111
+
112
+ Attacher.validate do
113
+ validate_max_size 10 * 1024 * 1024
114
+ end
115
+ end
116
+ ```
117
+ ```rb
118
+ photo = Photo.new
119
+ photo.image = file
120
+ photo.valid?
121
+ photo.errors #=> { image: ["size must not be greater than 10.0 MB"] }
45
122
  ```
46
123
 
47
- ## Validations
124
+ #### Attachment Presence
48
125
 
49
- Additionally, any Shrine validation errors will added to Sequel's errors upon
50
- validation. Note that if you want to validate presence of the attachment, you
51
- can do it directly on the model.
126
+ If you want to validate presence of the attachment, you can use Sequel's
127
+ presence validator:
52
128
 
53
129
  ```rb
54
- class User < Sequel::Model
55
- include ImageUploader::Attachment.new(:avatar)
56
- validates_presence_of :avatar
130
+ class Photo < Sequel::Model
131
+ include ImageUploader::Attachment(:image)
132
+
133
+ def validate
134
+ super
135
+ validates_presence :image
136
+ end
57
137
  end
58
138
  ```
59
139
 
60
- If don't want the attachment module to merge file validations errors into model
61
- errors, you can disable it:
140
+ #### Skipping Validations
141
+
142
+ If don't want the attachment module to merge file validations errors into
143
+ model errors, you can set `:validations` to `false`:
62
144
 
63
145
  ```rb
64
146
  plugin :sequel, validations: false
65
147
  ```
66
148
 
67
- [sequel]: /lib/shrine/plugins/sequel.rb
149
+ ## Attacher
150
+
151
+ You can also use `Shrine::Attacher` directly (with or without the
152
+ `Shrine::Attachment` module):
153
+
154
+ ```rb
155
+ class Photo < Sequel::Model # has `image_data` column
156
+ end
157
+ ```
158
+ ```rb
159
+ photo = Photo.new
160
+ attacher = ImageUploader::Attacher.from_model(photo, :image)
161
+
162
+ attacher.assign(file) # cache
163
+
164
+ attacher.file #=> #<Shrine::UploadedFile id="bc2e13.jpg" storage=:cache ...>
165
+ photo.image_data #=> '{"id":"bc2e13.jpg","storage":"cache","metadata":{...}}'
166
+
167
+ photo.save # persist
168
+ attacher.finalize # promote
169
+ photo.save # persist
170
+
171
+ attacher.file #=> #<Shrine::UploadedFile id="397eca.jpg" storage=:store ...>
172
+ photo.image_data #=> '{"id":"397eca.jpg","storage":"store","metadata":{...}}'
173
+ ```
174
+
175
+ ### Persistence
176
+
177
+ The following persistence methods are added to `Shrine::Attacher`:
178
+
179
+ | Method | Description |
180
+ | :----- | :---------- |
181
+ | `Attacher#atomic_promote` | calls `Attacher#promote` and persists if the attachment hasn't changed |
182
+ | `Attacher#atomic_persist` | saves changes if the attachment hasn't changed |
183
+ | `Attacher#persist` | saves any changes to the underlying record |
184
+
185
+ See [persistence] docs for more details.
186
+
187
+ [sequel]: https://github.com/shrinerb/shrine/blob/master/lib/shrine/plugins/sequel.rb
188
+ [Sequel]: https://sequel.jeremyevans.net/
189
+ [model]: https://shrinerb.com/docs/plugins/model
190
+ [validation]: https://shrinerb.com/docs/plugins/validation
191
+ [persistence]: https://shrinerb.com/docs/plugins/persistence