shrine 3.0.1 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of shrine might be problematic. Click here for more details.

Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +16 -0
  3. data/LICENSE.txt +1 -1
  4. data/README.md +7 -2
  5. data/doc/advantages.md +29 -12
  6. data/doc/carrierwave.md +54 -22
  7. data/doc/changing_derivatives.md +39 -39
  8. data/doc/getting_started.md +63 -58
  9. data/doc/multiple_files.md +5 -3
  10. data/doc/paperclip.md +92 -33
  11. data/doc/plugins/activerecord.md +1 -1
  12. data/doc/plugins/data_uri.md +2 -2
  13. data/doc/plugins/derivation_endpoint.md +26 -28
  14. data/doc/plugins/derivatives.md +170 -142
  15. data/doc/plugins/determine_mime_type.md +2 -2
  16. data/doc/plugins/infer_extension.md +2 -2
  17. data/doc/plugins/instrumentation.md +1 -1
  18. data/doc/plugins/metadata_attributes.md +21 -10
  19. data/doc/plugins/persistence.md +1 -0
  20. data/doc/plugins/refresh_metadata.md +5 -4
  21. data/doc/plugins/remote_url.md +2 -2
  22. data/doc/plugins/signature.md +11 -2
  23. data/doc/plugins/store_dimensions.md +2 -2
  24. data/doc/plugins/upload_endpoint.md +7 -11
  25. data/doc/plugins/validation_helpers.md +3 -3
  26. data/doc/processing.md +5 -5
  27. data/doc/refile.md +30 -9
  28. data/doc/release_notes/2.19.0.md +1 -1
  29. data/doc/release_notes/3.0.1.md +4 -0
  30. data/doc/release_notes/3.1.0.md +73 -0
  31. data/doc/securing_uploads.md +1 -1
  32. data/doc/storage/file_system.md +1 -1
  33. data/doc/storage/s3.md +1 -5
  34. data/doc/upgrading_to_3.md +4 -2
  35. data/doc/validation.md +3 -2
  36. data/lib/shrine.rb +1 -2
  37. data/lib/shrine/attacher.rb +4 -4
  38. data/lib/shrine/attachment.rb +3 -3
  39. data/lib/shrine/plugins/add_metadata.rb +1 -5
  40. data/lib/shrine/plugins/default_storage.rb +6 -6
  41. data/lib/shrine/plugins/derivatives.rb +4 -3
  42. data/lib/shrine/plugins/signature.rb +7 -6
  43. data/lib/shrine/plugins/store_dimensions.rb +18 -9
  44. data/lib/shrine/uploaded_file.rb +0 -1
  45. data/lib/shrine/version.rb +2 -2
  46. metadata +3 -2
@@ -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
 
@@ -70,7 +70,7 @@ payload:
70
70
 
71
71
  A default log subscriber is added as well which logs these events:
72
72
 
73
- ```plaintext
73
+ ```
74
74
  Extension (5ms) – {:mime_type=>"image/jpeg", :uploader=>Shrine}
75
75
  ```
76
76
 
@@ -81,7 +81,7 @@ plugin :infer_extension, log_subscriber: -> (event) {
81
81
  Shrine.logger.info JSON.generate(name: event.name, duration: event.duration, **event.payload)
82
82
  }
83
83
  ```
84
- ```plaintext
84
+ ```
85
85
  {"name":"extension","duration":5,"mime_type":"image/jpeg","uploader":"Shrine"}
86
86
  ```
87
87
 
@@ -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,5 @@ 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
@@ -89,3 +89,4 @@ attacher.persist # saves the underlying record
89
89
 
90
90
  [activerecord]: https://shrinerb.com/docs/plugins/activerecord
91
91
  [sequel]: https://shrinerb.com/docs/plugins/sequel
92
+ [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
@@ -166,7 +166,7 @@ following payload:
166
166
 
167
167
  A default log subscriber is added as well which logs these events:
168
168
 
169
- ```plaintext
169
+ ```
170
170
  Remote URL (1550ms) – {:remote_url=>"https://example.com/image.jpg",:download_options=>{},:uploader=>Shrine}
171
171
  ```
172
172
 
@@ -177,7 +177,7 @@ plugin :remote_url, log_subscriber: -> (event) {
177
177
  Shrine.logger.info JSON.generate(name: event.name, duration: event.duration, **event.payload)
178
178
  }
179
179
  ```
180
- ```plaintext
180
+ ```
181
181
  {"name":"remote_url","duration":5,"remote_url":"https://example.com/image.jpg","download_options":{},"uploader":"Shrine"}
182
182
  ```
183
183
 
@@ -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
 
@@ -110,7 +110,7 @@ following payload:
110
110
 
111
111
  A default log subscriber is added as well which logs these events:
112
112
 
113
- ```plaintext
113
+ ```
114
114
  Image Dimensions (108ms) – {:io=>File, :uploader=>Shrine}
115
115
  ```
116
116
 
@@ -121,7 +121,7 @@ plugin :store_dimensions, log_subscriber: -> (event) {
121
121
  Shrine.logger.info JSON.generate(name: event.name, duration: event.duration, **event.payload)
122
122
  }
123
123
  ```
124
- ```plaintext
124
+ ```
125
125
  {"name":"image_dimensions","duration":114,"io":"#<File:0x00007fc445371d90>","uploader":"Shrine"}
126
126
  ```
127
127
 
@@ -95,16 +95,9 @@ plugin :upload_endpoint, max_size: 20*1024*1024 # 20 MB
95
95
  If the uploaded file is larger than the specified value, a `413 Payload Too
96
96
  Large` response will be returned.
97
97
 
98
- ## Context
98
+ ## Uploader options
99
99
 
100
- The upload context will *not* contain `:record` and `:name` values, as the
101
- upload happens independently of a database record. The endpoint will send the
102
- following upload context:
103
-
104
- * `:action` – holds the value `:upload`
105
- * `:request` – holds an instance of `Rack::Request`
106
-
107
- You can update the upload context via `:upload_context`:
100
+ You can pass additional uploader options via `:upload_context`:
108
101
 
109
102
  ```rb
110
103
  plugin :upload_endpoint, upload_context: -> (request) do
@@ -112,13 +105,16 @@ plugin :upload_endpoint, upload_context: -> (request) do
112
105
  end
113
106
  ```
114
107
 
108
+ Note that the uploader will *not* receive `:record` and `:name` values, as the
109
+ upload happens independently of a database record.
110
+
115
111
  ## Upload
116
112
 
117
113
  You can also customize the upload itself via the `:upload` option:
118
114
 
119
115
  ```rb
120
- plugin :upload_endpoint, upload: -> (io, context, request) do
121
- Shrine.upload(io, :cache, context)
116
+ plugin :upload_endpoint, upload: -> (io, **options, request) do
117
+ Shrine.upload(io, :cache, **options)
122
118
  end
123
119
  ```
124
120
 
@@ -150,11 +150,11 @@ the `:default_messages` option to the plugin:
150
150
  ```rb
151
151
  plugin :validation_helpers, default_messages: {
152
152
  max_size: -> (max) { I18n.t("errors.file.max_size", max: max) },
153
- min_size: -> (max) { I18n.t("errors.file.min_size", min: min) },
153
+ min_size: -> (min) { I18n.t("errors.file.min_size", min: min) },
154
154
  max_width: -> (max) { I18n.t("errors.file.max_width", max: max) },
155
- min_width: -> (max) { I18n.t("errors.file.min_width", min: min) },
155
+ min_width: -> (min) { I18n.t("errors.file.min_width", min: min) },
156
156
  max_height: -> (max) { I18n.t("errors.file.max_height", max: max) },
157
- min_height: -> (max) { I18n.t("errors.file.min_height", min: min) },
157
+ min_height: -> (min) { I18n.t("errors.file.min_height", min: min) },
158
158
  max_dimensions: -> (dims) { I18n.t("errors.file.max_dimensions", dims: dims) },
159
159
  min_dimensions: -> (dims) { I18n.t("errors.file.min_dimensions", dims: dims) },
160
160
  mime_type_inclusion: -> (list) { I18n.t("errors.file.mime_type_inclusion", list: list) },
@@ -13,7 +13,7 @@ processing with [ImageMagick]/[GraphicsMagick] (using the [MiniMagick] gem) or
13
13
  [libvips] (using the [ruby-vips] gem; see the [libvips section](#libvips)).
14
14
  Here is an example of generating a thumbnail with ImageProcessing:
15
15
 
16
- ```sh
16
+ ```
17
17
  $ brew install imagemagick
18
18
  ```
19
19
  ```rb
@@ -43,7 +43,7 @@ Shrine.plugin :derivatives
43
43
  require "image_processing/mini_magick"
44
44
 
45
45
  class ImageUploader < Shrine
46
- Attacher.derivatives_processor do |original|
46
+ Attacher.derivatives do |original|
47
47
  magick = ImageProcessing::MiniMagick.source(original)
48
48
 
49
49
  {
@@ -163,7 +163,7 @@ class ImageUploader < Shrine
163
163
  small: [300, 300],
164
164
  }
165
165
 
166
- Attacher.derivatives_processor do |original, name:|
166
+ Attacher.derivatives do |original, name:|
167
167
  thumbnail = ImageProcessing::MiniMagick
168
168
  .source(original)
169
169
  .resize_to_limit!(*THUMBNAILS.fetch(name))
@@ -223,7 +223,7 @@ gem "streamio-ffmpeg"
223
223
  require "streamio-ffmpeg"
224
224
 
225
225
  class VideoUploader < Shrine
226
- Attacher.derivatives_processor do |original|
226
+ Attacher.derivatives do |original|
227
227
  transcoded = Tempfile.new ["transcoded", ".mp4"]
228
228
  screenshot = Tempfile.new ["screenshot", ".jpg"]
229
229
 
@@ -306,7 +306,7 @@ low memory usage (see [Why is libvips quick]).
306
306
  Using libvips is as easy as installing it and switching to the
307
307
  `ImageProcessing::Vips` backend:
308
308
 
309
- ```sh
309
+ ```
310
310
  $ brew install vips
311
311
  ```
312
312
 
@@ -6,7 +6,7 @@ This guide is aimed at helping Refile users transition to Shrine, and it consist
6
6
  of three parts:
7
7
 
8
8
  1. Explanation of the key differences in design between Refile and Shrine
9
- 2. Instructions how to migrate and existing app that uses Refile to Shrine
9
+ 2. Instructions how to migrate an existing app that uses Refile to Shrine
10
10
  3. Extensive reference of Refile's interface with Shrine equivalents
11
11
 
12
12
  ## Overview
@@ -199,13 +199,18 @@ explains this setup in more detail.
199
199
  ## Migrating from Refile
200
200
 
201
201
  You have an existing app using Refile and you want to transfer it to
202
- Shrine. Let's assume we have a `Photo` model with the "image" attachment. First
203
- we need to create the `image_data` column for Shrine:
202
+ Shrine. Let's assume we have a `Photo` model with the "image" attachment.
203
+
204
+ ### 1. Add Shrine column
205
+
206
+ First we need to create the `image_data` column for Shrine:
204
207
 
205
208
  ```rb
206
209
  add_column :photos, :image_data, :text
207
210
  ```
208
211
 
212
+ ### 2. Dual write
213
+
209
214
  Afterwards we need to make new uploads write to the `image_data` column. This
210
215
  can be done by including the below module to all models that have Refile
211
216
  attachments:
@@ -219,8 +224,7 @@ Shrine.storages = {
219
224
  }
220
225
 
221
226
  Shrine.plugin :model
222
- ```
223
- ```rb
227
+
224
228
  module RefileShrineSynchronization
225
229
  def write_shrine_data(name)
226
230
  attacher = Shrine::Attacher.from_model(self, name)
@@ -257,8 +261,12 @@ end
257
261
  ```
258
262
 
259
263
  After you deploy this code, the `image_data` column should now be successfully
260
- synchronized with new attachments. Next step is to run a script which writes
261
- all existing Refile attachments to `image_data`:
264
+ synchronized with new attachments.
265
+
266
+ ### 3. Data migration
267
+
268
+ Next step is to run a script which writes all existing Refile attachments to
269
+ `image_data`:
262
270
 
263
271
  ```rb
264
272
  Photo.find_each do |photo|
@@ -267,9 +275,22 @@ Photo.find_each do |photo|
267
275
  end
268
276
  ```
269
277
 
278
+ ### 4. Rewrite code
279
+
270
280
  Now you should be able to rewrite your application so that it uses Shrine
271
- instead of Refile, using equivalent Shrine storages. For help with translating
272
- the code from Refile to Shrine, you can consult the reference below.
281
+ instead of Refile (you can consult the reference in the next section). You can
282
+ remove the `RefileShrineSynchronization` module as well.
283
+
284
+ ### 5. Remove Refile columns
285
+
286
+ If everything is looking good, we can remove Refile columns:
287
+
288
+ ```rb
289
+ remove_column :photos, :image_id
290
+ remove_column :photos, :image_size
291
+ remove_column :photos, :image_filename
292
+ remove_column :photos, :image_content_type
293
+ ```
273
294
 
274
295
  ## Refile to Shrine direct mapping
275
296
 
@@ -16,7 +16,7 @@ title: Shrine 2.19.0
16
16
  uploaded_file.download
17
17
  uploaded_file.delete
18
18
  ```
19
- ```plaintext
19
+ ```
20
20
  Metadata (32ms) – {:storage=>:store, :io=>StringIO, :uploader=>Shrine}
21
21
  Upload (1523ms) – {:storage=>:store, :location=>"ed0e30ddec8b97813f2c1f4cfd1700b4", :io=>StringIO, :upload_options=>{}, :uploader=>Shrine}
22
22
  Exists (755ms) – {:storage=>:store, :location=>"ed0e30ddec8b97813f2c1f4cfd1700b4", :uploader=>Shrine}
@@ -1,3 +1,7 @@
1
+ ---
2
+ title: Shrine 3.0.1
3
+ ---
4
+
1
5
  ## Regressions
2
6
 
3
7
  * Fixed `metadata_attributes` plugin raising an exception when the attachment
@@ -0,0 +1,73 @@
1
+ ---
2
+ title: Shrine 3.1.0
3
+ ---
4
+
5
+ ## New features
6
+
7
+ * The `Attacher#create_derivatives` method now accepts a `:storage` option for
8
+ specifying the storage to which derivatives should be uploaded.
9
+
10
+ ```rb
11
+ # with attachment module
12
+ photo.image_derivatives!(storage: :other_store)
13
+
14
+ # with attacher
15
+ attacher.create_derivatives(storage: :other_store)
16
+ ```
17
+
18
+ * The `Shrine.calculate_signature` now accepts a `:rewind` boolean option for
19
+ choosing whether the IO object should be rewinded after reading. This is
20
+ useful if you want to calculate signature from non-rewindable IO objects,
21
+ such as `IO.pipe`, `Socket`, non-rewindable `Down::ChunkedIO` etc.
22
+
23
+ ```rb
24
+ Shrine.signature(io, rewind: false)
25
+ ```
26
+
27
+ ## Improvements
28
+
29
+ * The derivatives processor can now be registered with `Attacher.derivatives`,
30
+ which is just an alias for `Attacher.derivatives_processor`.
31
+
32
+ ```rb
33
+ class ImageUploader < Shrine
34
+ Attacher.derivatives_processor do |original|
35
+ # ...
36
+ end
37
+ end
38
+
39
+ # can now be written as
40
+
41
+ class ImageUploader < Shrine
42
+ Attacher.derivatives do |original|
43
+ # ...
44
+ end
45
+ end
46
+ ```
47
+
48
+ * The `Attacher#cached?` and `Attacher#stored?` methods now work correctly if
49
+ temporary/permanent storage identifiers were specified as strings.
50
+
51
+ * The `store_dimensions` plugin now properly propagates exceptions when loading
52
+ the `ruby-vips` gem in `:vips` analyzer.
53
+
54
+ * The `add_metadata` plugin now respects inheritance again when defining
55
+ metadata methods on the `Shrine::UploadedFile` class. In 2.19.0, the
56
+ `add_metadata` plugin was changed to define metadata methods on the internal
57
+ `FileMethods` plugin module, which is shared across all uploaders. This
58
+ change has now been reverted.
59
+
60
+ ## Backwards compatibility
61
+
62
+ * The `Attacher#cache_key` and `Attacher#store_key` methods now always return
63
+ symbol keys, even if the storage key that was specified was a string key.
64
+
65
+ ```rb
66
+ attacher = Shrine::Attacher.new(cache: "cache", store: "store")
67
+ attacher.cache_key #=> :cache (previously "cache")
68
+ attacher.store_key #=> :store (previously "store")
69
+ ```
70
+
71
+ * The `add_metadata` plugin now defines metadata methods directly on the
72
+ `UploadedFile` class, which means that if you happen to have been overriding
73
+ these metadata methods and calling `super`, this won't work anymore.