shrine 3.0.1 → 3.3.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 (103) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +82 -0
  3. data/LICENSE.txt +1 -1
  4. data/README.md +15 -5
  5. data/doc/advantages.md +33 -16
  6. data/doc/attacher.md +2 -2
  7. data/doc/carrierwave.md +78 -34
  8. data/doc/changing_derivatives.md +39 -39
  9. data/doc/design.md +134 -85
  10. data/doc/direct_s3.md +1 -0
  11. data/doc/external/articles.md +57 -45
  12. data/doc/external/extensions.md +41 -35
  13. data/doc/external/misc.md +23 -8
  14. data/doc/getting_started.md +177 -112
  15. data/doc/metadata.md +79 -43
  16. data/doc/multiple_files.md +6 -4
  17. data/doc/paperclip.md +119 -42
  18. data/doc/plugins/activerecord.md +1 -1
  19. data/doc/plugins/add_metadata.md +112 -35
  20. data/doc/plugins/atomic_helpers.md +41 -3
  21. data/doc/plugins/backgrounding.md +12 -2
  22. data/doc/plugins/column.md +36 -7
  23. data/doc/plugins/data_uri.md +2 -2
  24. data/doc/plugins/default_url.md +6 -3
  25. data/doc/plugins/derivation_endpoint.md +26 -28
  26. data/doc/plugins/derivatives.md +238 -171
  27. data/doc/plugins/determine_mime_type.md +2 -2
  28. data/doc/plugins/download_endpoint.md +5 -5
  29. data/doc/plugins/dynamic_storage.md +1 -1
  30. data/doc/plugins/form_assign.md +5 -5
  31. data/doc/plugins/included.md +25 -5
  32. data/doc/plugins/infer_extension.md +11 -2
  33. data/doc/plugins/instrumentation.md +1 -1
  34. data/doc/plugins/metadata_attributes.md +22 -10
  35. data/doc/plugins/mirroring.md +1 -1
  36. data/doc/plugins/persistence.md +11 -1
  37. data/doc/plugins/refresh_metadata.md +5 -4
  38. data/doc/plugins/remote_url.md +8 -3
  39. data/doc/plugins/remove_invalid.md +9 -1
  40. data/doc/plugins/signature.md +11 -2
  41. data/doc/plugins/store_dimensions.md +12 -2
  42. data/doc/plugins/type_predicates.md +96 -0
  43. data/doc/plugins/upload_endpoint.md +7 -11
  44. data/doc/plugins/upload_options.md +1 -1
  45. data/doc/plugins/url_options.md +4 -4
  46. data/doc/plugins/validation.md +14 -4
  47. data/doc/plugins/validation_helpers.md +3 -3
  48. data/doc/plugins/versions.md +7 -7
  49. data/doc/processing.md +290 -127
  50. data/doc/refile.md +39 -18
  51. data/doc/release_notes/2.19.0.md +1 -1
  52. data/doc/release_notes/2.8.0.md +1 -1
  53. data/doc/release_notes/3.0.0.md +1 -1
  54. data/doc/release_notes/3.0.1.md +4 -0
  55. data/doc/release_notes/3.1.0.md +73 -0
  56. data/doc/release_notes/3.2.0.md +96 -0
  57. data/doc/release_notes/3.2.1.md +31 -0
  58. data/doc/release_notes/3.2.2.md +14 -0
  59. data/doc/release_notes/3.3.0.md +105 -0
  60. data/doc/securing_uploads.md +3 -3
  61. data/doc/storage/file_system.md +1 -1
  62. data/doc/storage/memory.md +19 -0
  63. data/doc/storage/s3.md +105 -82
  64. data/doc/testing.md +2 -2
  65. data/doc/upgrading_to_3.md +97 -49
  66. data/doc/validation.md +3 -2
  67. data/lib/shrine.rb +8 -8
  68. data/lib/shrine/attacher.rb +24 -14
  69. data/lib/shrine/attachment.rb +5 -5
  70. data/lib/shrine/plugins.rb +22 -0
  71. data/lib/shrine/plugins/activerecord.rb +1 -1
  72. data/lib/shrine/plugins/add_metadata.rb +18 -7
  73. data/lib/shrine/plugins/backgrounding.rb +2 -2
  74. data/lib/shrine/plugins/default_storage.rb +6 -6
  75. data/lib/shrine/plugins/default_url.rb +1 -1
  76. data/lib/shrine/plugins/derivation_endpoint.rb +12 -7
  77. data/lib/shrine/plugins/derivatives.rb +61 -29
  78. data/lib/shrine/plugins/determine_mime_type.rb +3 -3
  79. data/lib/shrine/plugins/entity.rb +6 -6
  80. data/lib/shrine/plugins/mirroring.rb +8 -8
  81. data/lib/shrine/plugins/model.rb +3 -3
  82. data/lib/shrine/plugins/presign_endpoint.rb +16 -4
  83. data/lib/shrine/plugins/pretty_location.rb +1 -1
  84. data/lib/shrine/plugins/processing.rb +1 -1
  85. data/lib/shrine/plugins/refresh_metadata.rb +2 -2
  86. data/lib/shrine/plugins/remote_url.rb +3 -3
  87. data/lib/shrine/plugins/remove_attachment.rb +5 -0
  88. data/lib/shrine/plugins/remove_invalid.rb +10 -5
  89. data/lib/shrine/plugins/sequel.rb +1 -1
  90. data/lib/shrine/plugins/signature.rb +7 -6
  91. data/lib/shrine/plugins/store_dimensions.rb +22 -11
  92. data/lib/shrine/plugins/type_predicates.rb +113 -0
  93. data/lib/shrine/plugins/upload_endpoint.rb +10 -5
  94. data/lib/shrine/plugins/upload_options.rb +2 -2
  95. data/lib/shrine/plugins/url_options.rb +2 -2
  96. data/lib/shrine/plugins/validation.rb +9 -7
  97. data/lib/shrine/storage/linter.rb +4 -4
  98. data/lib/shrine/storage/memory.rb +5 -3
  99. data/lib/shrine/storage/s3.rb +117 -38
  100. data/lib/shrine/uploaded_file.rb +0 -1
  101. data/lib/shrine/version.rb +2 -2
  102. data/shrine.gemspec +7 -8
  103. metadata +25 -31
@@ -106,7 +106,7 @@ payload:
106
106
 
107
107
  A default log subscriber is added as well which logs these events:
108
108
 
109
- ```plaintext
109
+ ```
110
110
  MIME Type (33ms) – {:io=>StringIO, :uploader=>Shrine}
111
111
  ```
112
112
 
@@ -117,7 +117,7 @@ plugin :determine_mime_type, log_subscriber: -> (event) {
117
117
  Shrine.logger.info JSON.generate(name: event.name, duration: event.duration, **event.payload)
118
118
  }
119
119
  ```
120
- ```plaintext
120
+ ```
121
121
  {"name":"mime_type","duration":24,"io":"#<StringIO:0x00007fb7c5b08b80>","uploader":"Shrine"}
122
122
  ```
123
123
 
@@ -87,6 +87,10 @@ class DownloadsController < ApplicationController
87
87
  end
88
88
  ```
89
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.
93
+
90
94
  ## Host
91
95
 
92
96
  You can specify download URL host via the `:host` plugin option:
@@ -155,11 +159,6 @@ You can override any of the options above when creating the endpoint:
155
159
  Shrine.download_endpoint(disposition: "attachment")
156
160
  ```
157
161
 
158
- ## Custom endpoint
159
-
160
- If you want to have more control on download requests, you can use the
161
- `rack_response` plugin which this plugin uses internally.
162
-
163
162
  ## Plugin options
164
163
 
165
164
  | Name | Description | Default |
@@ -171,3 +170,4 @@ If you want to have more control on download requests, you can use the
171
170
  | `:redirect` | Whether to redirect to uploaded files on the storage | `false` |
172
171
 
173
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
@@ -12,7 +12,7 @@ Example:
12
12
  plugin :dynamic_storage
13
13
 
14
14
  storage /store_(\w+)/ do |match|
15
- Shrine::Storages::S3.new(bucket: match[1])
15
+ Shrine::Storage::S3.new(bucket: match[1])
16
16
  end
17
17
  ```
18
18
 
@@ -14,7 +14,7 @@ the attacher:
14
14
 
15
15
  ```rb
16
16
  attacher = photo.image_attacher
17
- attacher.form_assign("image" => file, "title" => "...", "description" => "...")
17
+ attacher.form_assign({ "image" => file, "title" => "...", "description" => "..." })
18
18
  attacher.file #=> #<Shrine::UploadedFile>
19
19
  ```
20
20
 
@@ -22,17 +22,17 @@ It works with `remote_url`, `data_uri`, and `remove_attachment` plugins:
22
22
 
23
23
  ```rb
24
24
  # remote_url plugin
25
- attacher.form_assign("image_remote_url" => "https://example.com/...")
25
+ attacher.form_assign({ "image_remote_url" => "https://example.com/..." })
26
26
  attacher.file #=> #<Shrine::UploadedFile>
27
27
  ```
28
28
  ```rb
29
29
  # data_uri plugin
30
- attacher.form_assign("image_data_uri" => "data:image/jpeg;base64,...")
30
+ attacher.form_assign({ "image_data_uri" => "data:image/jpeg;base64,..." })
31
31
  attacher.file #=> #<Shrine::UploadedFile>
32
32
  ```
33
33
  ```rb
34
34
  # remove_attachment plugin
35
- attacher.form_assign("remove_image" => "1")
35
+ attacher.form_assign({ "remove_image" => "1" })
36
36
  attacher.file #=> nil
37
37
  ```
38
38
 
@@ -40,7 +40,7 @@ The return value is a hash with form params, with file param replaced with
40
40
  cached file data, which can later be assigned again to the record.
41
41
 
42
42
  ```rb
43
- attacher.form_assign("image" => file, "title" => "...", "description" => "...")
43
+ attacher.form_assign({ "image" => file, "title" => "...", "description" => "..." })
44
44
  #=> { :image => '{"id":"...","storage":"...","metadata":"..."}', "title" => "...", "description" => "..." }
45
45
  ```
46
46
 
@@ -7,15 +7,35 @@ of the attachment module, and call additional methods on the model that
7
7
  includes it.
8
8
 
9
9
  ```rb
10
- plugin :included do |name|
11
- # called when attachment module is included into a model
10
+ class ImageUploader < Shrine
11
+ plugin :included do |name|
12
+ # called when attachment module is included into a model
12
13
 
13
- self #=> #<Photo>
14
- name #=> :image
14
+ self #=> Photo (the model class)
15
+ name #=> :image
16
+ end
15
17
  end
16
18
  ```
17
19
  ```rb
18
- Photo.include Shrine::Attachment(:image)
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:
26
+
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
19
39
  ```
20
40
 
21
41
  [included]: https://github.com/shrinerb/shrine/blob/master/lib/shrine/plugins/included.rb
@@ -11,6 +11,15 @@ extension might not be known.
11
11
  plugin :infer_extension
12
12
  ```
13
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
+
14
23
  ## Inferrers
15
24
 
16
25
  By default, the [mini_mime] gem will be used for inferring the extension, but
@@ -70,7 +79,7 @@ payload:
70
79
 
71
80
  A default log subscriber is added as well which logs these events:
72
81
 
73
- ```plaintext
82
+ ```
74
83
  Extension (5ms) – {:mime_type=>"image/jpeg", :uploader=>Shrine}
75
84
  ```
76
85
 
@@ -81,7 +90,7 @@ plugin :infer_extension, log_subscriber: -> (event) {
81
90
  Shrine.logger.info JSON.generate(name: event.name, duration: event.duration, **event.payload)
82
91
  }
83
92
  ```
84
- ```plaintext
93
+ ```
85
94
  {"name":"extension","duration":5,"mime_type":"image/jpeg","uploader":"Shrine"}
86
95
  ```
87
96
 
@@ -34,7 +34,7 @@ uploaded_file.exists?
34
34
  uploaded_file.download
35
35
  uploaded_file.delete
36
36
  ```
37
- ```plaintext
37
+ ```
38
38
  Metadata (32ms) – {:storage=>:store, :io=>StringIO, :uploader=>Shrine}
39
39
  Upload (1523ms) – {:storage=>:store, :location=>"ed0e30ddec8b97813f2c1f4cfd1700b4", :io=>StringIO, :upload_options=>{}, :uploader=>Shrine}
40
40
  Exists (755ms) – {:storage=>:store, :location=>"ed0e30ddec8b97813f2c1f4cfd1700b4", :uploader=>Shrine}
@@ -2,21 +2,18 @@
2
2
  title: Metadata Attributes
3
3
  ---
4
4
 
5
- The [`metadata_attributes`][metadata_attributes] plugin allows you to sync
6
- attachment metadata to additional record attributes. You can provide a hash of
7
- mappings to the plugin call itself or the `Attacher.metadata_attributes`
8
- method:
5
+ The [`metadata_attributes`][metadata_attributes] plugin allows you to write
6
+ attachment metadata to additional record attributes. You can configure the
7
+ plugin with a hash of mappings:
9
8
 
10
9
  ```rb
11
10
  plugin :metadata_attributes, :size => :size, :mime_type => :type
12
-
13
11
  # or
14
-
15
12
  plugin :metadata_attributes
16
13
  Attacher.metadata_attributes :size => :size, :mime_type => :type
17
14
  ```
18
15
 
19
- The above configuration will sync `size` metadata field to `<attachment>_size`
16
+ The above configuration will write `size` metadata field to `<attachment>_size`
20
17
  record attribute, and `mime_type` metadata field to `<attachment>_type` record
21
18
  attribute.
22
19
 
@@ -32,6 +29,18 @@ user.avatar_size #=> nil
32
29
  user.avatar_type #=> nil
33
30
  ```
34
31
 
32
+ ## Model and Entity
33
+
34
+ With the [`model`][model] plugin, any method that internally calls
35
+ `Attacher#write` will trigger metadata attributes writing (`Attacher#assign`,
36
+ `Attacher#attach`, `Attacher#change`, `Attacher#set`).
37
+
38
+ ```rb
39
+ attacher.file.metadata["mime_type"] = "other/type"
40
+ attacher.write
41
+ attacher.record.avatar_type #=> "other/type"
42
+ ```
43
+
35
44
  If you're using the [`entity`][entity] plugin, metadata attributes will be
36
45
  added to `Attacher#column_values`:
37
46
 
@@ -45,6 +54,11 @@ attacher.column_values #=>
45
54
  # }
46
55
  ```
47
56
 
57
+ Any metadata attributes that were declared but are missing on the record will
58
+ be skipped.
59
+
60
+ ## Full attribute name
61
+
48
62
  If you want to specify the full record attribute name, pass the record
49
63
  attribute name as a string instead of a symbol.
50
64
 
@@ -56,8 +70,6 @@ photo.image = image
56
70
  photo.original_filename #=> "nature.jpg"
57
71
  ```
58
72
 
59
- Any metadata attributes that were declared but are missing on the record will
60
- be skipped.
61
-
62
73
  [metadata_attributes]: https://github.com/shrinerb/shrine/blob/master/lib/shrine/plugins/metadata_attributes.rb
63
74
  [entity]: https://shrinerb.com/docs/plugins/entity
75
+ [model]: https://shrinerb.com/docs/plugins/model
@@ -50,7 +50,7 @@ Shrine.plugin :mirroring, mirror: { ... }, delete: false
50
50
  You can have mirroring performed in a background job:
51
51
 
52
52
  ```rb
53
- Shrine.mirror_upload_block do |file|
53
+ Shrine.mirror_upload_block do |file, **options|
54
54
  MirrorUploadJob.perform_async(file.shrine_class.name, file.data)
55
55
  end
56
56
 
@@ -6,6 +6,10 @@ This is an internal plugin that provides uniform persistence interface across
6
6
  different persistence plugins (e.g. [`activerecord`][activerecord],
7
7
  [`sequel`][sequel]).
8
8
 
9
+ For these activerecord and sequel, atomic persistence is implemented in terms
10
+ of database locks, eg "SELECT... FOR UPDATE". For more discussion of concurrency
11
+ challenges, see the [atomic_helpers] documentation.
12
+
9
13
  ## Atomic promotion
10
14
 
11
15
  If you're promoting cached file to permanent storage
@@ -65,11 +69,15 @@ changed, and if it hasn't the attachment is persisted. If the attachment has
65
69
  changed, `Shrine::AttachmentChanged` exception is raised.
66
70
 
67
71
  If you want to execute code after the attachment change check but before
68
- persistence, you can pass a block:
72
+ persistence, you can pass a block. For instance, one way to allow concurrent
73
+ changes to metadata, perhaps in different background workers, without
74
+ overwriting each other might be:
69
75
 
70
76
  ```rb
71
77
  attacher.atomic_persist do |reloaded_attacher|
72
78
  # run code after attachment change check but before persistence
79
+ attacher.file.metadata.merge!(reloaded_attacher.file.metadata)
80
+ attacher.file.metadata["some_key"] = "changed_value"
73
81
  end
74
82
  ```
75
83
 
@@ -89,3 +97,5 @@ attacher.persist # saves the underlying record
89
97
 
90
98
  [activerecord]: https://shrinerb.com/docs/plugins/activerecord
91
99
  [sequel]: https://shrinerb.com/docs/plugins/sequel
100
+ [atomic_helpers]: https://shrinerb.com/docs/plugins/atomic_helpers
101
+ [backgrounding]: https://shrinerb.com/docs/plugins/backgrounding
@@ -12,17 +12,18 @@ plugin :refresh_metadata
12
12
  It provides `#refresh_metadata!` method, which triggers metadata extraction
13
13
  (calls `Shrine#extract_metadata`) with the uploaded file opened for reading,
14
14
  and updates the existing metadata hash with the results. This can be done
15
- on the attacher or the uploaded file level.
15
+ on the `Shrine::Attacher` or the `Shrine::UploadedFile` level.
16
16
 
17
17
  ## Attacher
18
18
 
19
19
  Calling `#refresh_metadata!` on a `Shrine::Attacher` object will re-extract
20
- metadata of the attached file. When used with a [model], it will write new file
21
- data back into the attachment attribute.
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
22
 
23
23
  ```rb
24
24
  attacher.refresh_metadata!
25
- attacher.file.metadata # re-extracted metadata
25
+ attacher.file.metadata # re-extracted metadata
26
+ attacher.record.file_data #=> '{ ... data with updated metadata ... }'
26
27
  ```
27
28
 
28
29
  The `Attacher#context` hash will be forwarded to metadata extraction, as well
@@ -40,7 +40,12 @@ around [open-uri].
40
40
  You can pass options to the downloader via the `:downloader` option:
41
41
 
42
42
  ```rb
43
- attacher.assign_remote_url(url, downloader: { 'Authorization' => 'Basic ...' })
43
+ attacher.assign_remote_url url, downloader: {
44
+ headers: { "Authorization" => "Basic ..." },
45
+ read_timeout: 30, open_timeout: 30,
46
+ max_redirects: 5,
47
+ # ...
48
+ }
44
49
  ```
45
50
 
46
51
  You can also change the downloader:
@@ -166,7 +171,7 @@ following payload:
166
171
 
167
172
  A default log subscriber is added as well which logs these events:
168
173
 
169
- ```plaintext
174
+ ```
170
175
  Remote URL (1550ms) – {:remote_url=>"https://example.com/image.jpg",:download_options=>{},:uploader=>Shrine}
171
176
  ```
172
177
 
@@ -177,7 +182,7 @@ plugin :remote_url, log_subscriber: -> (event) {
177
182
  Shrine.logger.info JSON.generate(name: event.name, duration: event.duration, **event.payload)
178
183
  }
179
184
  ```
180
- ```plaintext
185
+ ```
181
186
  {"name":"remote_url","duration":5,"remote_url":"https://example.com/image.jpg","download_options":{},"uploader":"Shrine"}
182
187
  ```
183
188
 
@@ -11,9 +11,17 @@ plugin :remove_invalid
11
11
  ```
12
12
 
13
13
  ```rb
14
- photo.image = file # invalid file
14
+ # without previous file
15
+ photo.image #=> nil
16
+ photo.image = file # validation fails, assignment is reverted
15
17
  photo.valid? #=> false
16
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" ...>
17
25
  ```
18
26
 
19
27
  [remove_invalid]: https://github.com/shrinerb/shrine/blob/master/lib/shrine/plugins/remove_invalid.rb
@@ -55,6 +55,15 @@ add_metadata :md5 do |io, action: nil, **|
55
55
  end
56
56
  ```
57
57
 
58
+ ## Rewinding
59
+
60
+ If you want to calculate signature from a non-rewindable IO object, you can
61
+ tell Shrine to skip rewinding:
62
+
63
+ ```rb
64
+ Shrine.calculate_signature(io, :md5, rewind: false)
65
+ ```
66
+
58
67
  ## Instrumentation
59
68
 
60
69
  If the `instrumentation` plugin has been loaded, the `signature` plugin adds
@@ -76,7 +85,7 @@ following payload:
76
85
 
77
86
  A default log subscriber is added as well which logs these events:
78
87
 
79
- ```plaintext
88
+ ```
80
89
  MIME Type (33ms) – {:io=>StringIO, :uploader=>Shrine}
81
90
  ```
82
91
 
@@ -87,7 +96,7 @@ plugin :signature, log_subscriber: -> (event) {
87
96
  Shrine.logger.info JSON.generate(name: event.name, duration: event.duration, **event.payload)
88
97
  }
89
98
  ```
90
- ```plaintext
99
+ ```
91
100
  {"name":"signature","duration":24,"io":"#<StringIO:0x00007fb7c5b08b80>","uploader":"Shrine"}
92
101
  ```
93
102
 
@@ -72,6 +72,16 @@ Shrine.dimensions(io) #=> [300, 400] (calls the defined analyzer)
72
72
  Shrine.dimensions_analyzers[:fastimage].call(io) #=> [300, 400] (calls a built-in analyzer)
73
73
  ```
74
74
 
75
+ ### Disabling auto-extraction
76
+
77
+ If you want to use the dimensions extraction methods but not automatically
78
+ extract dimensions on upload, you can setup this plugin with the
79
+ `auto_extraction: false` option.
80
+
81
+ ```rb
82
+ plugin :store_dimensions, auto_extraction: false
83
+ ```
84
+
75
85
  ## Errors
76
86
 
77
87
  By default, any exceptions that the analyzer raises while extracting dimensions
@@ -110,7 +120,7 @@ following payload:
110
120
 
111
121
  A default log subscriber is added as well which logs these events:
112
122
 
113
- ```plaintext
123
+ ```
114
124
  Image Dimensions (108ms) – {:io=>File, :uploader=>Shrine}
115
125
  ```
116
126
 
@@ -121,7 +131,7 @@ plugin :store_dimensions, log_subscriber: -> (event) {
121
131
  Shrine.logger.info JSON.generate(name: event.name, duration: event.duration, **event.payload)
122
132
  }
123
133
  ```
124
- ```plaintext
134
+ ```
125
135
  {"name":"image_dimensions","duration":114,"io":"#<File:0x00007fc445371d90>","uploader":"Shrine"}
126
136
  ```
127
137
 
@@ -0,0 +1,96 @@
1
+ ---
2
+ title: Type Predicates
3
+ ---
4
+
5
+ The [`type_predicates`][type_predicates] plugin adds predicate methods to
6
+ `Shrine::UploadedFile` based on the MIME type. By default, it uses the
7
+ [MiniMime] gem for looking up MIME types.
8
+
9
+ ```rb
10
+ # Gemfile
11
+ gem "mini_mime"
12
+ ```
13
+ ```rb
14
+ Shrine.plugin :type_predicates
15
+ ```
16
+
17
+ ## General predicates
18
+
19
+ The plugin adds four predicate methods based on the general type of the file:
20
+
21
+ ```rb
22
+ file.image? # returns true for any "image/*" MIME type
23
+ file.video? # returns true for any "video/*" MIME type
24
+ file.audio? # returns true for any "audio/*" MIME type
25
+ file.text? # returns true for any "text/*" MIME type
26
+ ```
27
+
28
+ If `mime_type` metadata value is nil, `Shrine::Error` will be raised.
29
+
30
+ ## Specific predicates
31
+
32
+ The `UploadedFile#type?` method takes a file extension, and returns whether the
33
+ `mime_type` metadata value of the uploaded file matches the MIME type
34
+ associated to the given file extension.
35
+
36
+ ```rb
37
+ file.type?(:jpg) # returns true if MIME type is "image/jpeg"
38
+ file.type?(:svg) # returns true if MIME type is "image/svg+xml"
39
+ file.type?(:mov) # returns true if MIME type is "video/quicktime"
40
+ file.type?(:ppt) # returns true if MIME type is "application/vnd.ms-powerpoint"
41
+ ...
42
+ ```
43
+
44
+ For convenience, you can create predicate methods for specific file types:
45
+
46
+ ```rb
47
+ Shrine.plugin :type_predicates, methods: %i[jpg svg mov ppt]
48
+ ```
49
+ ```rb
50
+ file.jpg? # returns true if MIME type is "image/jpeg"
51
+ file.svg? # returns true if MIME type is "image/svg+xml"
52
+ file.mov? # returns true if MIME type is "video/quicktime"
53
+ file.ppt? # returns true if MIME type is "application/vnd.ms-powerpoint"
54
+ ```
55
+
56
+ If `mime_type` metadata value is nil, or the underlying MIME type library
57
+ doesn't recognize a given type, `Shrine::Error` will be raised.
58
+
59
+ ### MIME database
60
+
61
+ The MIME type lookup by file extension is done by the underlying MIME type
62
+ library ([MiniMime] by default). You can change the MIME type library via the
63
+ `:mime` plugin option:
64
+
65
+ ```rb
66
+ Shrine.plugin :type_predicates, mime: :marcel # requires adding "marcel" gem to the Gemfile
67
+ ```
68
+
69
+ The following MIME type libraries are supported:
70
+
71
+ | Name | Description |
72
+ | :---- | :--------- |
73
+ | `:mini_mime` | (**Default**.) Uses [MiniMime] gem to look up MIME type by extension. |
74
+ | `:mime_types` | Uses [mime-types] gem to look up MIME type by extension. |
75
+ | `:mimemagic` | Uses [MimeMagic] gem to look up MIME type by extension. |
76
+ | `:marcel` | Uses [Marcel] gem to look up MIME type by extension. |
77
+ | `:rack_mime` | Uses [Rack::Mime] to look up MIME type by extension. |
78
+
79
+ You can also specify a custom block, which receives the extension and is
80
+ expected to return the corresponding MIME type. Inside the block you can call
81
+ into existing MIME type libraries:
82
+
83
+ ```rb
84
+ Shrine.plugin :type_predicates, mime: -> (extension) do
85
+ mime_type = Shrine.type_lookup(extension, :marcel)
86
+ mime_type ||= Shrine.type_lookup(extension, :mini_mime)
87
+ mime_type
88
+ end
89
+ ```
90
+
91
+ [type_predicates]: https://github.com/shrinerb/shrine/blob/master/lib/shrine/plugins/type_predicates.rb
92
+ [MiniMime]: https://github.com/discourse/mini_mime
93
+ [mime-types]: https://github.com/mime-types/ruby-mime-types
94
+ [MimeMagic]: https://github.com/minad/mimemagic
95
+ [Marcel]: https://github.com/basecamp/marcel
96
+ [Rack::Mime]: https://github.com/rack/rack/blob/master/lib/rack/mime.rb