shrine 3.6.0 → 3.7.1

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 (59) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +24 -0
  3. data/doc/changing_derivatives.md +2 -1
  4. data/doc/changing_location.md +17 -5
  5. data/doc/getting_started.md +4 -2
  6. data/doc/plugins/derivation_endpoint.md +15 -1
  7. data/doc/plugins/derivatives.md +2 -1
  8. data/doc/plugins/download_endpoint.md +16 -4
  9. data/doc/plugins/rack_response.md +9 -0
  10. data/doc/plugins/refresh_metadata.md +20 -0
  11. data/doc/plugins/signature.md +8 -6
  12. data/doc/processing.md +5 -3
  13. data/doc/release_notes/3.7.0.md +75 -0
  14. data/doc/release_notes/3.7.1.md +13 -0
  15. data/lib/shrine/attacher.rb +21 -21
  16. data/lib/shrine/attachment.rb +2 -2
  17. data/lib/shrine/plugins/_persistence.rb +1 -1
  18. data/lib/shrine/plugins/_urlsafe_serialization.rb +4 -4
  19. data/lib/shrine/plugins/add_metadata.rb +2 -4
  20. data/lib/shrine/plugins/atomic_helpers.rb +7 -7
  21. data/lib/shrine/plugins/backgrounding.rb +9 -9
  22. data/lib/shrine/plugins/column.rb +6 -4
  23. data/lib/shrine/plugins/data_uri.rb +1 -1
  24. data/lib/shrine/plugins/default_url.rb +4 -4
  25. data/lib/shrine/plugins/delete_raw.rb +2 -2
  26. data/lib/shrine/plugins/derivation_endpoint.rb +29 -27
  27. data/lib/shrine/plugins/derivatives.rb +5 -1
  28. data/lib/shrine/plugins/download_endpoint.rb +62 -10
  29. data/lib/shrine/plugins/entity.rb +7 -7
  30. data/lib/shrine/plugins/infer_extension.rb +1 -1
  31. data/lib/shrine/plugins/instrumentation.rb +8 -8
  32. data/lib/shrine/plugins/metadata_attributes.rb +1 -1
  33. data/lib/shrine/plugins/mirroring.rb +10 -10
  34. data/lib/shrine/plugins/model.rb +9 -9
  35. data/lib/shrine/plugins/presign_endpoint.rb +4 -4
  36. data/lib/shrine/plugins/pretty_location.rb +2 -2
  37. data/lib/shrine/plugins/processing.rb +3 -3
  38. data/lib/shrine/plugins/rack_file.rb +2 -2
  39. data/lib/shrine/plugins/rack_response.rb +6 -6
  40. data/lib/shrine/plugins/refresh_metadata.rb +6 -6
  41. data/lib/shrine/plugins/remote_url.rb +4 -4
  42. data/lib/shrine/plugins/restore_cached_data.rb +3 -3
  43. data/lib/shrine/plugins/signature.rb +2 -2
  44. data/lib/shrine/plugins/store_dimensions.rb +2 -2
  45. data/lib/shrine/plugins/upload_endpoint.rb +4 -4
  46. data/lib/shrine/plugins/upload_options.rb +1 -1
  47. data/lib/shrine/plugins/validation.rb +8 -8
  48. data/lib/shrine/plugins/validation_helpers.rb +1 -1
  49. data/lib/shrine/plugins/versions.rb +10 -10
  50. data/lib/shrine/plugins.rb +6 -14
  51. data/lib/shrine/storage/file_system.rb +4 -17
  52. data/lib/shrine/storage/linter.rb +8 -8
  53. data/lib/shrine/storage/memory.rb +1 -3
  54. data/lib/shrine/storage/s3.rb +45 -37
  55. data/lib/shrine/uploaded_file.rb +20 -18
  56. data/lib/shrine/version.rb +2 -2
  57. data/lib/shrine.rb +18 -18
  58. data/shrine.gemspec +6 -6
  59. metadata +16 -17
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a5fadb4e660b7638e1d17b81ecb1761e8dd5faa675f15a3b30de0c549bafd653
4
- data.tar.gz: a9ee826b483ab474f55ac66bc35e95a4cb8496cada12ce7595091210670f1f38
3
+ metadata.gz: 29a02d25cd1180c4f0170434edd185b3b1ab0bd2be060fa53e58fcd32c50d4ae
4
+ data.tar.gz: 56e50d961ef88e0d3cae4d295b6996c52cd2021b923d9b453f401f10b04021b3
5
5
  SHA512:
6
- metadata.gz: 2c0f867b7215189135563524f9e7d8cf28d8be1a5b298bc173bbe1af9fb3ced15f98dd198c8cb13bfa87abdf3eb29566083c6ebc1de0955713da6c165562c41d
7
- data.tar.gz: 47c2f75d9a831fdc1d731086fbeeb5a6885a1845eac375a5ba2ce9b5354654f49931e6b26f2732d98edfa39cbfcf3e587be63f01490910a06a7bad64cea8219e
6
+ metadata.gz: cb06f261af63f09ba767556d65f8b99e5204c1162ce7d8e28e5355148539a02c486fa088819884cf38dee4bf0683e8167b6582c4a028271a5145bd8661f64765
7
+ data.tar.gz: ec5cd4f04fe90ada87cd594bf78e61c2de9fcbebe8d51cb9e49b0bec566614be5ea5826382a8f25608888c84a951f25ad80442a6af2d641a37bae0e8fe184d7e
data/CHANGELOG.md CHANGED
@@ -1,3 +1,27 @@
1
+ ## 3.7.1 (2026-06-03)
2
+
3
+ * Update method signatures of some plugins to work around a Bootsnap bug causing a `wrong number of arguments` error.
4
+
5
+ ## 3.7.0 (2026-05-27)
6
+
7
+ * `rack_response` - Add `:etag` option for setting a custom `ETag` header (@janko)
8
+
9
+ * `download_endpoint` - Add support for expiring URLs (@davidwessman)
10
+
11
+ * `s3` - Use `TransferManager` where available instead of deprecated `upload_steam` (@danieldevlewis)
12
+
13
+ * `column` - Don't attempt to deserialize empty string as JSON (@adam12)
14
+
15
+ * `derivatives` - Add `:keep_derivatives` plugin option to keep existing derivatives when a new file is attached (@fnordfish)
16
+
17
+ * `refresh_metadata` - Add `replace:` keyword argument to `refresh_metadata!` for replacing instead of merging existing metadata (@JacobGalati)
18
+
19
+ * `backgrounding` - Fix options not being forwarded from `promote_cached` to `promote_block` (@4ndypanda)
20
+
21
+ * Fix URI default parser warnings in `UploadedFile` (@adam12)
22
+
23
+ * Drop support for Ruby < 3.2
24
+
1
25
  ## 3.6.0 (2024-04-29)
2
26
 
3
27
  * Add Rack 3 support (@tomasc, @janko)
@@ -36,7 +36,8 @@ derivatives generated). Let's assume you're generating image thumbnails:
36
36
 
37
37
  ```rb
38
38
  # Gemfile
39
- gem "image_processing", "~> 1.8"
39
+ gem "image_processing", "~> 2.0"
40
+ gem "mini_magick", "~> 5.0"
40
41
  ```
41
42
  ```rb
42
43
  require "image_processing/mini_magick"
@@ -3,7 +3,7 @@ id: changing-location
3
3
  title: Migrating File Locations
4
4
  ---
5
5
 
6
- This guide shows how to migrate the location of uploaded files on the same
6
+ This guide shows how to migrate the location of uploaded files on the same
7
7
  storage in production, with zero downtime.
8
8
 
9
9
  Let's assume we have a `Photo` model with an `image` file attachment:
@@ -31,20 +31,32 @@ to work with the previously stored urls because the files have not been migrated
31
31
  ```rb
32
32
  class ImageUploader < Shrine
33
33
  def generate_location(io, **options)
34
- # change location generation
34
+ # change location generation, eg....
35
+ [
36
+ options[:record] && options[:record].class.name.underscore,
37
+ option[:record] && options[:record].id,
38
+ super
39
+ ].compact.join("/")
35
40
  end
36
41
  end
37
42
  ```
38
43
 
39
- We can now deploy this change to production so new file uploads will be stored in
44
+ We can now deploy this change to production so new file uploads will be stored in
40
45
  the new location.
41
46
 
47
+ As seen above, we can call `super` to get the include the default location, which uses ruby
48
+ `SecureRandom.hex` to have a unique immutable storage location. While it isn't
49
+ strictly required to have a unique immutable storage location, it makes many
50
+ things work smoother when different content will get a different storage location,
51
+ and is recommended. One approach is using fixed directory/prefix as above.
52
+
53
+
42
54
  ## 2. Move existing files
43
55
 
44
56
  To move existing files to new location, run the following script. It fetches
45
57
  the photos in batches, downloads the image, and re-uploads it to the new location.
46
- We only need to migrate the files in `:store` storage need to be migrated as the files
47
- in `:cache` storage will be uploaded to the new location on promotion.
58
+ Only the files in `:store` storage need to be migrated as the files in `:cache`
59
+ storage will be uploaded to the new location on promotion.
48
60
 
49
61
  ```rb
50
62
  Photo.find_each do |photo|
@@ -602,7 +602,8 @@ creation:
602
602
 
603
603
  ```rb
604
604
  # Gemfile
605
- gem "image_processing", "~> 1.8"
605
+ gem "image_processing", "~> 2.0"
606
+ gem "mini_magick", "~> 5.0"
606
607
  ```
607
608
  ```rb
608
609
  Shrine.plugin :derivatives, create_on_promote: true
@@ -656,7 +657,8 @@ processing we want to perform:
656
657
 
657
658
  ```rb
658
659
  # Gemfile
659
- gem "image_processing", "~> 1.8"
660
+ gem "image_processing", "~> 2.0"
661
+ gem "mini_magick", "~> 5.0"
660
662
  ```
661
663
  ```rb
662
664
  # config/initializers/rails.rb (Rails)
@@ -35,7 +35,8 @@ apply to an attached file. For example, we can generate image thumbnails using
35
35
  the [ImageProcessing] gem:
36
36
 
37
37
  ```rb
38
- gem "image_processing", "~> 1.8"
38
+ gem "image_processing", "~> 2.0"
39
+ gem "mini_magick", "~> 5.0"
39
40
  ```
40
41
  ```rb
41
42
  require "image_processing/mini_magick"
@@ -308,6 +309,19 @@ uploaded_file.derivation_url(:thumbnail, prefix: "transformations/image")
308
309
  #=> ".../transformations/image/thumbnail/eyJpZCI6ImZvbyIsInN?signature=..."
309
310
  ```
310
311
 
312
+ ## Format
313
+
314
+ Some HTTP clients and CDNs use the URL path extension to determine the content
315
+ type of the response. You can append a file extension to the derivation URL
316
+ path with the `:format` option:
317
+
318
+ ```rb
319
+ uploaded_file.derivation_url(:thumbnail, format: "jpg")
320
+ #=> ".../thumbnail/eyJpZCI6ImZvbyIsInN.jpg?signature=..."
321
+ ```
322
+
323
+ The extension is included in the URL signature, so it cannot be tampered with.
324
+
311
325
  ## Expiration
312
326
 
313
327
  By default derivation URLs are valid indefinitely. If you want URLs to expire
@@ -20,7 +20,8 @@ Here is an example of generating image thumbnails:
20
20
 
21
21
  ```rb
22
22
  # Gemfile
23
- gem "image_processing", "~> 1.8"
23
+ gem "image_processing", "~> 2.0"
24
+ gem "mini_magick", "~> 5.0"
24
25
  ```
25
26
  ```rb
26
27
  require "image_processing/mini_magick"
@@ -7,7 +7,7 @@ downloading uploaded files from specified storages. This can be useful when
7
7
  files from your storage isn't accessible over URL (e.g. database storages) or
8
8
  if you want to authenticate your downloads.
9
9
 
10
- ## Global Endpoint
10
+ ## Global Endpoint
11
11
 
12
12
  You can configure the plugin with the path prefix which the endpoint will be
13
13
  mounted on.
@@ -34,6 +34,7 @@ Links to the download endpoint are generated by calling
34
34
  ```rb
35
35
  uploaded_file.download_url #=> "/attachments/eyJpZCI6ImFkdzlyeTM..."
36
36
  ```
37
+
37
38
  ## Endpoint via Uploader
38
39
 
39
40
  You can also configure the plugin in the uploader directly - just make sure to mount it via your Uploader-class.
@@ -52,8 +53,8 @@ Rails.application.routes.draw do
52
53
  end
53
54
  ```
54
55
 
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)*
56
+ _Hint: For shrine versions 2.x -> ensure that you don't include the plugin
57
+ twice (globally and in your uploader class - see #408)_
57
58
 
58
59
  ## Calling from a controller
59
60
 
@@ -69,6 +70,7 @@ Rails.application.routes.draw do
69
70
  get "/attachments/*rest", to: "downloads#image"
70
71
  end
71
72
  ```
73
+
72
74
  ```rb
73
75
  # app/controllers/downloads_controller.rb (Rails)
74
76
  class DownloadsController < ApplicationController
@@ -131,6 +133,16 @@ plugin :download_endpoint, download_options: -> (uploaded_file, request) {
131
133
  }
132
134
  ```
133
135
 
136
+ ## Expiring download urls
137
+
138
+ If you want to have URLs that expire after a certain time, you can use the `:expires_in` and `secret_key` options:
139
+
140
+ ```rb
141
+ plugin :download_endpoint, expires_in: 5 * 60, secret_key: "secret"
142
+ ```
143
+
144
+ this will generate URLs that are signed with a signature valid for 5 minutes.
145
+
134
146
  ## Performance considerations
135
147
 
136
148
  Streaming files through the app might impact the request throughput, depending
@@ -162,7 +174,7 @@ Shrine.download_endpoint(disposition: "attachment")
162
174
  ## Plugin options
163
175
 
164
176
  | Name | Description | Default |
165
- | :-------- | :---------- | :------ |
177
+ | :------------------ | :-------------------------------------------------------------------------------- | :------- |
166
178
  | `:disposition` | Whether browser should render the file `inline` or download it as an `attachment` | `inline` |
167
179
  | `:download_options` | Hash of storage-specific options passed to `Storage#open` | `{}` |
168
180
  | `:host` | URL host that will be added to download URLs | `nil` |
@@ -95,6 +95,15 @@ headers["Content-Range"] #=> "bytes 100-200/1000"
95
95
  body # partial content
96
96
  ```
97
97
 
98
+ ## ETag
99
+
100
+ A custom ETag value can be provided via the `:etag` option:
101
+
102
+ ```rb
103
+ response = uploaded_file.to_rack_response(etag: "my-custom-etag")
104
+ response[1]["ETag"] #=> "my-custom-etag"
105
+ ```
106
+
98
107
  ## Download options
99
108
 
100
109
  The `#to_rack_response` method will automatically open the `UploadedFile` if it
@@ -69,5 +69,25 @@ Any options passed in will be forwarded to metadata extraction:
69
69
  uploaded_file.refresh_metadata!(foo: "bar") # passes `{ foo: "bar" }` options to metadata extraction
70
70
  ```
71
71
 
72
+ ## Replacing Metadata
73
+
74
+ By default the `#refresh_metadata!` method will merge the results into any existing metadata.
75
+
76
+ ```rb
77
+ uploaded_file.metadata["custom"] = "custom value"
78
+ uploaded_file.refresh_metadata!
79
+ uploaded_file.metadata
80
+ # returns {"filename"=>"example.jpg", "size"=>1024, "mime_type"=>"image/jpeg", "custom"=>"custom value"}
81
+ ```
82
+
83
+ Passing `replace: true` will instead fully overwrite the existing metadata with the new metadata.
84
+
85
+ ```rb
86
+ uploaded_file.metadata["custom"] = "custom value"
87
+ uploaded_file.refresh_metadata!(replace: true)
88
+ uploaded_file.metadata
89
+ # returns {"filename"=>"example.jpg", "size"=>1024, "mime_type"=>"image/jpeg"}
90
+ ```
91
+
72
92
  [refresh_metadata]: https://github.com/shrinerb/shrine/blob/master/lib/shrine/plugins/refresh_metadata.rb
73
93
  [model]: https://shrinerb.com/docs/plugins/model
@@ -78,15 +78,17 @@ plugin :signature
78
78
  Calculating signature will trigger a `signature.shrine` event with the
79
79
  following payload:
80
80
 
81
- | Key | Description |
82
- | :-- | :---- |
83
- | `:io` | The IO object |
84
- | `:uploader` | The uploader class that sent the event |
81
+ | Key | Description |
82
+ | :-- | :---- |
83
+ | `:algorithm` | The hashing algorithm used |
84
+ | `:format` | The encoding format |
85
+ | `:io` | The IO object |
86
+ | `:uploader` | The uploader class that sent the event |
85
87
 
86
88
  A default log subscriber is added as well which logs these events:
87
89
 
88
90
  ```
89
- MIME Type (33ms) – {:io=>StringIO, :uploader=>Shrine}
91
+ Signature (1ms) – {io: StringIO, algorithm: :md5, format: :hex, uploader: Shrine}
90
92
  ```
91
93
 
92
94
  You can also use your own log subscriber:
@@ -97,7 +99,7 @@ plugin :signature, log_subscriber: -> (event) {
97
99
  }
98
100
  ```
99
101
  ```
100
- {"name":"signature","duration":24,"io":"#<StringIO:0x00007fb7c5b08b80>","uploader":"Shrine"}
102
+ {"name":"signature","duration":24,"io":"#<StringIO:0x00007fb7c5b08b80>","algorithm":"sha512","format":"hex","uploader":"Shrine"}
101
103
  ```
102
104
 
103
105
  Or disable logging altogether:
data/doc/processing.md CHANGED
@@ -18,7 +18,8 @@ $ brew install imagemagick
18
18
  ```
19
19
  ```rb
20
20
  # Gemfile
21
- gem "image_processing", "~> 1.8"
21
+ gem "image_processing", "~> 2.0"
22
+ gem "mini_magick", "~> 5.0"
22
23
  ```
23
24
  ```rb
24
25
  require "image_processing/mini_magick"
@@ -405,7 +406,7 @@ Shrine integration, the ImageProcessing gem that we saw earlier is a completely
405
406
  generic gem.
406
407
 
407
408
  To demonstrate, here is an example of transcoding videos using
408
- [streamio-ffmpeg]:
409
+ [streamio-ffmpeg][streamio-ffmpeg]:
409
410
 
410
411
  ```rb
411
412
  # Gemfile
@@ -502,7 +503,8 @@ $ brew install vips
502
503
 
503
504
  ```rb
504
505
  # Gemfile
505
- gem "image_processing", "~> 1.8"
506
+ gem "image_processing", "~> 2.0"
507
+ gem "ruby-vips", "~> 2.3"
506
508
  ```
507
509
 
508
510
  ```rb
@@ -0,0 +1,75 @@
1
+ ---
2
+ title: Shrine 3.7.0
3
+ ---
4
+
5
+ ## New features
6
+
7
+ * The `download_endpoint` plugin now supports expiring URLs. Configure a `secret_key` and optionally a default `expires_in` on the plugin, then pass `expires_in:` when generating a URL. The URL is signed with HMAC-SHA256, and the endpoint will reject requests with an expired or tampered signature.
8
+
9
+ ```rb
10
+ plugin :download_endpoint,
11
+ prefix: "downloads",
12
+ secret_key: "<your-secret-key>",
13
+ expires_in: 5 * 60 # optional default; can be overridden per URL
14
+ ```
15
+
16
+ ```rb
17
+ uploaded_file.download_url # uses the default expires_in
18
+ uploaded_file.download_url(expires_in: 10 * 60) # override per URL
19
+ # => "https://example.com/downloads/<token>?signature=...&expires_at=..."
20
+ ```
21
+
22
+ * The `derivatives` plugin now accepts a `:keep_derivatives` option. When set to `true`, existing derivatives are kept when a new file is attached via `Attacher#change`, instead of being cleared.
23
+
24
+ ```rb
25
+ plugin :derivatives, keep_derivatives: true
26
+ ```
27
+
28
+ ```rb
29
+ attacher.derivatives #=> { thumb: #<Shrine::UploadedFile> }
30
+ attacher.change(new_file)
31
+ attacher.derivatives #=> { thumb: #<Shrine::UploadedFile> } # preserved
32
+ ```
33
+
34
+ * The `refresh_metadata` plugin now accepts a `replace:` keyword argument on `refresh_metadata!`. Passing `replace: true` replaces the file's metadata entirely with the freshly extracted values, instead of merging them. This is useful when you want to remove stale custom metadata keys.
35
+
36
+ ```rb
37
+ uploaded_file.metadata["custom"] = "stale value"
38
+
39
+ uploaded_file.refresh_metadata! # merge (default)
40
+ uploaded_file.metadata["custom"] #=> "stale value" (preserved)
41
+
42
+ uploaded_file.refresh_metadata!(replace: true) # replace
43
+ uploaded_file.metadata["custom"] #=> nil (removed)
44
+ ```
45
+
46
+ ## Other improvements
47
+
48
+ * The `s3` storage now prefers using `TransferManager#upload_stream` over the deprecated `#upload_stream` method on the S3 object, when `TransferManager` is available. This avoids deprecation warnings from newer versions of the AWS SDK.
49
+
50
+ * The `column` plugin no longer attempts to deserialize an empty string as JSON. Previously this would raise a parse error; now the attachment is treated as blank.
51
+
52
+ * The `backgrounding` plugin now correctly forwards keyword arguments passed to `Attacher#promote_cached` into the `promote_block` callback.
53
+
54
+ ```rb
55
+ Shrine::Attacher.promote_block do |attacher:, my_option:, **|
56
+ # my_option was previously not forwarded here
57
+ SomePromoteJob.perform_async(attacher.dump, my_option: my_option)
58
+ end
59
+
60
+ attacher.promote_cached(my_option: "value") # now forwarded correctly
61
+ ```
62
+
63
+ * `UploadedFile` no longer produces URI default parser warnings (`URI::RFC3986_PARSER.make_regexp is obsolete`) when verbose warnings are enabled.
64
+
65
+ ## Backwards compatibility
66
+
67
+ * Support for Ruby versions below 3.2 has been dropped. Ruby >= 3.2 is now required.
68
+
69
+ * ImageProcessing 2.0 made `mini_magick` and `ruby-vips` soft dependencies that are no longer loaded automatically. If you use either gem for image processing, you will need to add it explicitly to your `Gemfile`:
70
+
71
+ ```rb
72
+ gem "mini_magick"
73
+ # or
74
+ gem "ruby-vips"
75
+ ```
@@ -0,0 +1,13 @@
1
+ ---
2
+ title: Shrine 3.7.1
3
+ ---
4
+
5
+ ## Bug fixes
6
+
7
+ * When initializing Shrine with the `activerecord` plugin, under Bootsnap 1.24.5 and Ruby 3.4.5 this would raise an error:
8
+
9
+ ```
10
+ ArgumentError: wrong number of arguments (given 2, expected 1; required keyword: plugin)
11
+ ```
12
+
13
+ The seems to be triggered by a special combination of method signatures, where keyword arguments get converted into positional arguments under Bootsnap. To work around this issue, method signatures of some plugin methods have been updated.
@@ -22,8 +22,8 @@ class Shrine
22
22
  #
23
23
  # attacher = Attacher.from_data({ "id" => "...", "storage" => "...", "metadata" => { ... } })
24
24
  # attacher.file #=> #<Shrine::UploadedFile>
25
- def from_data(data, **options)
26
- attacher = new(**options)
25
+ def from_data(data, **)
26
+ attacher = new(**)
27
27
  attacher.load_data(data)
28
28
  attacher
29
29
  end
@@ -47,14 +47,14 @@ class Shrine
47
47
  end
48
48
 
49
49
  # Returns the temporary storage identifier.
50
- def cache_key; @cache.to_sym; end
50
+ def cache_key = @cache.to_sym
51
51
  # Returns the permanent storage identifier.
52
- def store_key; @store.to_sym; end
52
+ def store_key = @store.to_sym
53
53
 
54
54
  # Returns the uploader that is used for the temporary storage.
55
- def cache; shrine_class.new(cache_key); end
55
+ def cache = shrine_class.new(cache_key)
56
56
  # Returns the uploader that is used for the permanent storage.
57
- def store; shrine_class.new(store_key); end
57
+ def store = shrine_class.new(store_key)
58
58
 
59
59
  # Calls #attach_cached, but skips if value is an empty string (this is
60
60
  # useful when the uploaded file comes from form fields). Forwards any
@@ -67,14 +67,14 @@ class Shrine
67
67
  #
68
68
  # # ignores the assignment when a blank string is given
69
69
  # attacher.assign("")
70
- def assign(value, **options)
70
+ def assign(value, **)
71
71
  return if value == "" # skip empty hidden field
72
72
 
73
73
  if value.is_a?(Hash) || value.is_a?(String)
74
74
  return if uploaded_file(value) == file # skip assignment for current file
75
75
  end
76
76
 
77
- attach_cached(value, **options)
77
+ attach_cached(value, **)
78
78
  end
79
79
 
80
80
  # Sets an existing cached file, or uploads an IO object to temporary
@@ -92,11 +92,11 @@ class Shrine
92
92
  #
93
93
  # # sets an existing cached file from Hash data
94
94
  # attacher.attach_cached({ "id" => "...", "storage" => "cache", "metadata" => {} })
95
- def attach_cached(value, **options)
95
+ def attach_cached(value, **)
96
96
  if value.is_a?(String) || value.is_a?(Hash)
97
- change(cached(value, **options))
97
+ change(cached(value, **))
98
98
  else
99
- attach(value, storage: cache_key, action: :cache, **options)
99
+ attach(value, storage: cache_key, action: :cache, **)
100
100
  end
101
101
  end
102
102
 
@@ -113,8 +113,8 @@ class Shrine
113
113
  #
114
114
  # # removes the attachment
115
115
  # attacher.attach(nil)
116
- def attach(io, storage: store_key, **options)
117
- file = upload(io, storage, **options) if io
116
+ def attach(io, storage: store_key, **)
117
+ file = upload(io, storage, **) if io
118
118
 
119
119
  change(file)
120
120
  end
@@ -158,8 +158,8 @@ class Shrine
158
158
  # attacher.cached? #=> true
159
159
  # attacher.promote_cached
160
160
  # attacher.stored? #=> true
161
- def promote_cached(**options)
162
- promote(**options) if promote?
161
+ def promote_cached(**)
162
+ promote(**) if promote?
163
163
  end
164
164
 
165
165
  # Uploads current file to permanent storage and sets the stored file.
@@ -167,8 +167,8 @@ class Shrine
167
167
  # attacher.cached? #=> true
168
168
  # attacher.promote
169
169
  # attacher.stored? #=> true
170
- def promote(storage: store_key, **options)
171
- set upload(file, storage, action: :store, **options)
170
+ def promote(storage: store_key, **)
171
+ set upload(file, storage, action: :store, **)
172
172
  end
173
173
 
174
174
  # Delegates to `Shrine.upload`, passing the #context.
@@ -178,8 +178,8 @@ class Shrine
178
178
  #
179
179
  # # pass additional options for the uploader
180
180
  # attacher.upload(io, :store, metadata: { "foo" => "bar" })
181
- def upload(io, storage = store_key, **options)
182
- shrine_class.upload(io, storage, **context, **options)
181
+ def upload(io, storage = store_key, **)
182
+ shrine_class.upload(io, storage, **context, **)
183
183
  end
184
184
 
185
185
  # If a new file was attached, deletes previously attached file if any.
@@ -249,8 +249,8 @@ class Shrine
249
249
  #
250
250
  # attacher.file = nil
251
251
  # attacher.url #=> nil
252
- def url(**options)
253
- file&.url(**options)
252
+ def url(**)
253
+ file&.url(**)
254
254
  end
255
255
 
256
256
  # Returns whether the attachment has changed.
@@ -22,8 +22,8 @@ class Shrine
22
22
  # Shorthand for `Attachment.new`.
23
23
  #
24
24
  # Shrine::Attachment[:image]
25
- def [](*args, **options)
26
- new(*args, **options)
25
+ def [](*, **)
26
+ new(*, **)
27
27
  end
28
28
  end
29
29
 
@@ -7,7 +7,7 @@ class Shrine
7
7
  #
8
8
  # plugin :_persistence, plugin: MyPlugin
9
9
  module Persistence
10
- def self.load_dependencies(uploader, *)
10
+ def self.load_dependencies(uploader, **)
11
11
  uploader.plugin :atomic_helpers
12
12
  uploader.plugin :entity
13
13
  end
@@ -23,8 +23,8 @@ class Shrine
23
23
  end
24
24
 
25
25
  module FileMethods
26
- def urlsafe_dump(**options)
27
- self.class.urlsafe_dump(self, **options)
26
+ def urlsafe_dump(**)
27
+ self.class.urlsafe_dump(self, **)
28
28
  end
29
29
 
30
30
  def urlsafe_data(metadata: [])
@@ -45,8 +45,8 @@ class Shrine
45
45
  end
46
46
 
47
47
  module FileClassMethods
48
- def urlsafe_dump(file, **options)
49
- data = file.urlsafe_data(**options)
48
+ def urlsafe_dump(file, **)
49
+ data = file.urlsafe_data(**)
50
50
 
51
51
  shrine_class.urlsafe_serialize(data)
52
52
  end
@@ -29,11 +29,9 @@ class Shrine
29
29
  end
30
30
 
31
31
  module InstanceMethods
32
- def extract_metadata(io, **options)
32
+ def extract_metadata(io, **)
33
33
  metadata = super
34
-
35
- extract_custom_metadata(io, **options, metadata: metadata)
36
-
34
+ extract_custom_metadata(io, **, metadata:)
37
35
  metadata
38
36
  end
39
37
 
@@ -14,14 +14,14 @@ class Shrine
14
14
  #
15
15
  # Shrine::Attacher.retrieve(model: photo, name: :image, file: file_data)
16
16
  # #=> #<ImageUploader::Attacher>
17
- def retrieve(model: nil, entity: nil, name:, file:, **options)
17
+ def retrieve(model: nil, entity: nil, name:, file:, **)
18
18
  fail ArgumentError, "either :model or :entity is required" unless model || entity
19
19
 
20
20
  record = model || entity
21
21
 
22
- attacher = record.send(:"#{name}_attacher", **options) if record.respond_to?(:"#{name}_attacher")
23
- attacher ||= from_model(record, name, **options) if model
24
- attacher ||= from_entity(record, name, **options) if entity
22
+ attacher = record.send(:"#{name}_attacher", **) if record.respond_to?(:"#{name}_attacher")
23
+ attacher ||= from_model(record, name, **) if model
24
+ attacher ||= from_entity(record, name, **) if entity
25
25
 
26
26
  if attacher.file != attacher.uploaded_file(file)
27
27
  fail Shrine::AttachmentChanged, "attachment has changed"
@@ -43,13 +43,13 @@ class Shrine
43
43
  #
44
44
  # This more convenient to use with concrete persistence plugins, which
45
45
  # provide defaults for reloading and persistence.
46
- def abstract_atomic_promote(reload:, persist:, **options, &block)
46
+ def abstract_atomic_promote(reload:, persist:, **, &block)
47
47
  original_file = file
48
48
 
49
- result = promote(**options)
49
+ result = promote(**)
50
50
 
51
51
  begin
52
- abstract_atomic_persist(original_file, reload: reload, persist: persist, &block)
52
+ abstract_atomic_persist(original_file, reload:, persist:, &block)
53
53
  result
54
54
  rescue Shrine::AttachmentChanged
55
55
  destroy_attached