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
@@ -1,12 +1,12 @@
1
1
  ---
2
- title: Shrine for Refile Users
2
+ title: Upgrading from Refile
3
3
  ---
4
4
 
5
5
  This guide is aimed at helping Refile users transition to Shrine, and it consists
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
@@ -110,13 +110,6 @@ into separate columns.
110
110
  Shrine provides on-the-fly processing via the
111
111
  [`derivation_endpoint`][derivation_endpoint] plugin:
112
112
 
113
- ```rb
114
- # config/routes.rb (Rails)
115
- Rails.application.routes.draw do
116
- # ...
117
- mount ImageUploader.derivation_endpoint => "/derivations/image"
118
- end
119
- ```
120
113
  ```rb
121
114
  require "image_processing/mini_magick"
122
115
 
@@ -132,8 +125,15 @@ class ImageUploader < Shrine
132
125
  end
133
126
  end
134
127
  ```
128
+ ```rb
129
+ # config/routes.rb (Rails)
130
+ Rails.application.routes.draw do
131
+ # ...
132
+ mount ImageUploader.derivation_endpoint => "/derivations/image"
133
+ end
134
+ ```
135
135
 
136
- Shrine also support processing up front using the [`derivatives`][derivatives]
136
+ Shrine also support eager processing using the [`derivatives`][derivatives]
137
137
  plugin.
138
138
 
139
139
  ### Validation
@@ -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,5 +1,5 @@
1
1
  ---
2
- title: Shrine 2.9.0
2
+ title: Shrine 2.8.0
3
3
  ---
4
4
 
5
5
  ## New Features
@@ -366,7 +366,7 @@ end
366
366
  ```
367
367
  ```rb
368
368
  attacher = photo.image_attacher
369
- attacher.form_assign("image" => file, "title" => "...", "description" => "...")
369
+ attacher.form_assign({ "image" => file, "title" => "...", "description" => "..." })
370
370
  attacher.file #=> #<Shrine::UploadedFile id="..." storage=:cache ...>
371
371
  ```
372
372
 
@@ -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.
@@ -0,0 +1,96 @@
1
+ ---
2
+ title: Shrine 3.2.0
3
+ ---
4
+
5
+ ## New features
6
+
7
+ * The `type_predicates` plugin has been added, which adds convenient predicate
8
+ methods to `Shrine::UploadedFile` based on the MIME type.
9
+
10
+ ```rb
11
+ # Gemfile
12
+ gem "mini_mime" # default dependency of type_predicates
13
+ ```
14
+ ```rb
15
+ Shrine.plugin :type_predicates
16
+ ```
17
+
18
+ The plugin adds four predicate methods based on the general type of the file:
19
+
20
+ ```rb
21
+ file.image? # returns true for any "image/*" MIME type
22
+ file.video? # returns true for any "video/*" MIME type
23
+ file.audio? # returns true for any "audio/*" MIME type
24
+ file.text? # returns true for any "text/*" MIME type
25
+ ```
26
+
27
+ You can also check for specific MIME type using the extension name:
28
+
29
+ ```rb
30
+ file.type?(:jpg) # returns true if MIME type is "image/jpeg"
31
+ file.type?(:svg) # returns true if MIME type is "image/svg+xml"
32
+ file.type?(:mov) # returns true if MIME type is "video/quicktime"
33
+ file.type?(:ppt) # returns true if MIME type is "application/vnd.ms-powerpoint"
34
+ ...
35
+ ```
36
+
37
+ For convenience, you can create predicate methods for specific file types:
38
+
39
+ ```rb
40
+ Shrine.plugin :type_predicates, methods: %i[jpg svg mov ppt]
41
+ ```
42
+ ```rb
43
+ file.jpg? # returns true if MIME type is "image/jpeg"
44
+ file.svg? # returns true if MIME type is "image/svg+xml"
45
+ file.mov? # returns true if MIME type is "video/quicktime"
46
+ file.ppt? # returns true if MIME type is "application/vnd.ms-powerpoint"
47
+ ```
48
+
49
+ * The `#add_metadata` method has been added to the `add_metadata` plugin for
50
+ adding new metadata to an existing file/attachment.
51
+
52
+ ```rb
53
+ attacher.file.metadata #=> { ... }
54
+ attacher.add_metadata("foo" => "bar")
55
+ attacher.file.metadata #=> { ..., "foo" => "bar" }
56
+ ```
57
+
58
+ ## Other improvements
59
+
60
+ * The `remove_invalid` plugin now works correctly with `derivatives` plugin.
61
+
62
+ * The `remove_invalid` plugin is now also activated when `Attacher#validate`
63
+ is called manually.
64
+
65
+ * The current attached file data can now be assigned back to the attachment
66
+ attribute, and this operation will be a no-op.
67
+
68
+ ```rb
69
+ photo.image #=> #<Shrine::UploadedFile id="foo" storage=:store metadata={...}>
70
+ photo.image = { "id" => "foo", "storage" => "store", "metadata" => { ... } } # no-op
71
+ ```
72
+
73
+ This allows treating the attachment attribute as a persistent attribute,
74
+ where the current value can be assigned back on record updates.
75
+
76
+ * When promoting derivatives, the `:derivative` parameter value was being
77
+ passed to the uploader as an array. This has been fixed, and the value is now
78
+ the same as when uploading derivatives directly to permanent storage.
79
+
80
+ * The `derivatives` plugin now includes additional `:io` and `:attacher` values
81
+ in the instrumentation event payload.
82
+
83
+ ## Backwards compatibility
84
+
85
+ * The `validation` plugin now runs validations on `Attacher#attach` and
86
+ `Attacher#attach_cached`. If you were using `Attacher#change` directly and
87
+ expecting the validations to be run automatically, you will need to update
88
+ your code.
89
+
90
+ * If you were updating the cached file metadata via file data assignment, this
91
+ will no longer work.
92
+
93
+ ```rb
94
+ photo.image #=> #<Shrine::UploadedFile id="foo" storage=:cache metadata={...}>
95
+ photo.image = { "id" => "foo", "storage" => "cache", "metadata" => { ... } } # no-op
96
+ ```
@@ -0,0 +1,31 @@
1
+ ---
2
+ title: Shrine 3.2.1
3
+ ---
4
+
5
+ ## Ruby 2.7 compatibility
6
+
7
+ * Shrine doesn't trigger [Ruby 2.7 warnings for separation of positional and
8
+ keyword arguments][kwargs] anymore.
9
+
10
+ * Down 5.1.0 has been released, which resolves warnings and a `FrozenError`
11
+ exception on Ruby 2.7. Shrine now requires at least this version of Down.
12
+
13
+ If you're using `Down::Http`, make sure you're using http.rb 4.3.0 or newer.
14
+
15
+ * ImageProcessing 1.10.3 gem has been released which resolves Ruby 2.7 warnings
16
+ as well. If you're using it for image processing, make sure to upgrade to
17
+ this version:
18
+
19
+ ```rb
20
+ gem "image_processing", ">= 1.10.3", "< 2"
21
+ ```
22
+
23
+ ## Rack 2.1 compatibility
24
+
25
+ * The `derivation_endpoint` plugin now uses `Rack::Files` on Rack 2.1 or newer.
26
+
27
+ ## Other improvements
28
+
29
+ * The `S3#open` method now handles empty S3 objects.
30
+
31
+ [kwargs]: https://www.ruby-lang.org/en/news/2019/12/12/separation-of-positional-and-keyword-arguments-in-ruby-3-0/
@@ -0,0 +1,14 @@
1
+ ---
2
+ title: Shrine 3.2.2
3
+ ---
4
+
5
+ ## Bug fixes
6
+
7
+ * aws-sdk-core 3.104.0 introduced a backwards incompatible changes that caused
8
+ `Shrine::Storage::S3#open` to start raising an exception.
9
+
10
+ ```
11
+ NoMethodError: undefined method `bytesize' for #<Array:0x000000000a721be0>
12
+ ```
13
+
14
+ This has now been fixed.
@@ -0,0 +1,105 @@
1
+ ---
2
+ title: Shrine 3.3.0
3
+ ---
4
+
5
+ ## New features
6
+
7
+ * The `:create_on_promote` option has been added to the `derivatives` plugin
8
+ for automatically creating derivatives after the attached cached file is
9
+ promoted to permanent storage.
10
+
11
+ ```rb
12
+ Shrine.plugin :derivatives, create_on_promote: true
13
+ ```
14
+
15
+ * The `:auto_extraction` option has been added to the `store_dimensions` plugin
16
+ for skipping automatically extracting dimensions on upload.
17
+
18
+ ```rb
19
+ Shrine.plugin :store_dimensions, auto_extraction: false
20
+ ```
21
+
22
+ * The `:skip_nil` option has been added to the `add_metadata` plugin for
23
+ excluding metadata keys whose values are nil.
24
+
25
+ ```rb
26
+ class PdfUploader < Shrine
27
+ add_metadata :pages, skip_nil: true do |io|
28
+ if is_pdf?(io)
29
+ reader = PDF::Reader.new(io)
30
+ reader.page_count
31
+ else
32
+ # If this is not a PDF, then the pages metadata will not be stored
33
+ nil
34
+ end
35
+ end
36
+ end
37
+ ```
38
+
39
+ * The `:download` option has been added to derivatives processors in
40
+ `derivatives` plugin for skipping converting the source IO object into a
41
+ file. This can be used to avoid a potentially expensive download/copy when
42
+ the derivatives processor doesn't need the file.
43
+
44
+ ```rb
45
+ Attacher.derivatives :my_processor, download: false do |source|
46
+ source #=> Could be File, Shrine::UploadedFile, or other IO-like object
47
+ shrine_class.with_file(source) do |file|
48
+ # can force download/copy if necessary with `with_file`,
49
+ end
50
+ end
51
+ ```
52
+
53
+ ## Bug fixes
54
+
55
+ * The `upload_endpoint` now handles calling `Shrine.upload_response` method
56
+ from a Rails controller.
57
+
58
+ * The `derivation_endpoint` plugin now applies the `version` query parameter
59
+ to the derivation when creating the response.
60
+
61
+ ## Other improvements
62
+
63
+ * The new `Aws:S3::EncryptionV2::Client` is now supported by the S3 storage for
64
+ client-side encryption.
65
+
66
+ * The `derivation_endpoint` now reduces the possibility of timing attacks by
67
+ comparing URL signatures in constant time using `Rack::Utils.secure_compare`.
68
+
69
+ * The `derivatives` plugin now copies non-file source IO objects to disk before
70
+ passing them to the processor. This is consistent with how a
71
+ `Shrine::UploadedFile` object is downloaded to disk.
72
+
73
+ * The `sequel` and `activerecord` plugins now call `Attacher#reload` when
74
+ reloading the model, which reloads the attached files but keeps other
75
+ attacher state.
76
+
77
+ * The `derivatives` plugin doesn't download the attached file anymore if
78
+ attempting to process derivatives when no derivatives processor was defined.
79
+
80
+ * The `mirroring` plugin now forwards attacher options when uploading to mirror
81
+ storages.
82
+
83
+ * The `presign_endpoint` plugin now handles the `OPTIONS` HTTP verb, which
84
+ newer versions of Uppy are requesting.
85
+
86
+ * `Shrine::Storage::Memory#open` now always returns a `StringIO` in the file
87
+ content's original encoding, instead of the encoding set by
88
+ `Encoding.default_internal`. This works around a [bug][ruby-lang #16497]
89
+ in `StringIO` introduced in Ruby 2.7.0.
90
+
91
+ * The `remove_attachment` plugin now deletes the removed file if a new file was
92
+ attached right after removal.
93
+
94
+ ## Backwards compatibility
95
+
96
+ * If you were passing a non-file IO object to the derivatives processor, Shrine
97
+ will now convert it into a file beforehand. If you're currently doing this
98
+ and are converting the IO object into a file inside the processor, you can
99
+ now remove the conversion code to avoid doubling the amount of disk writes.
100
+
101
+ * When reloading a Sequel/ActiveRecord model, any attacher state other than
102
+ uploaded files will now be retained after the reload. If you were relying on
103
+ all the attacher state being re-initialized, you'll need to update your code.
104
+
105
+ [ruby-lang #16497]: https://bugs.ruby-lang.org/issues/16497