shrine 3.3.0 → 3.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +42 -0
- data/README.md +14 -12
- data/doc/carrierwave.md +2 -2
- data/doc/changing_derivatives.md +1 -1
- data/doc/changing_location.md +8 -6
- data/doc/design.md +5 -5
- data/doc/direct_s3.md +25 -0
- data/doc/external/articles.md +16 -16
- data/doc/external/extensions.md +1 -1
- data/doc/getting_started.md +79 -27
- data/doc/metadata.md +1 -1
- data/doc/multiple_files.md +57 -22
- data/doc/paperclip.md +1 -0
- data/doc/plugins/backgrounding.md +4 -4
- data/doc/plugins/derivation_endpoint.md +24 -0
- data/doc/plugins/derivatives.md +11 -1
- data/doc/plugins/entity.md +12 -4
- data/doc/plugins/instrumentation.md +1 -1
- data/doc/plugins/keep_files.md +6 -4
- data/doc/plugins/model.md +8 -3
- data/doc/plugins/sequel.md +1 -1
- data/doc/plugins/validation_helpers.md +1 -1
- data/doc/processing.md +3 -2
- data/doc/refile.md +3 -3
- data/doc/release_notes/2.1.0.md +1 -1
- data/doc/release_notes/3.4.0.md +35 -0
- data/doc/release_notes/3.5.0.md +63 -0
- data/doc/retrieving_uploads.md +1 -1
- data/doc/testing.md +55 -17
- data/doc/upgrading_to_3.md +6 -8
- data/lib/shrine/plugins/activerecord.rb +3 -3
- data/lib/shrine/plugins/derivation_endpoint.rb +31 -30
- data/lib/shrine/plugins/derivatives.rb +25 -19
- data/lib/shrine/plugins/determine_mime_type.rb +2 -0
- data/lib/shrine/plugins/download_endpoint.rb +7 -0
- data/lib/shrine/plugins/entity.rb +14 -7
- data/lib/shrine/plugins/infer_extension.rb +4 -0
- data/lib/shrine/plugins/instrumentation.rb +17 -19
- data/lib/shrine/plugins/model.rb +3 -1
- data/lib/shrine/plugins/remove_attachment.rb +2 -0
- data/lib/shrine/plugins/sequel.rb +1 -1
- data/lib/shrine/plugins/validation_helpers.rb +1 -1
- data/lib/shrine/storage/s3.rb +17 -7
- data/lib/shrine/uploaded_file.rb +3 -2
- data/lib/shrine/version.rb +1 -1
- data/lib/shrine.rb +3 -3
- data/shrine.gemspec +3 -2
- metadata +26 -10
data/doc/multiple_files.md
CHANGED
@@ -3,6 +3,9 @@ id: multiple-files
|
|
3
3
|
title: Multiple Files
|
4
4
|
---
|
5
5
|
|
6
|
+
import Tabs from '@theme/Tabs';
|
7
|
+
import TabItem from '@theme/TabItem';
|
8
|
+
|
6
9
|
There are times when you want to allow users to attach multiple files to a
|
7
10
|
single resource, like an album having many photos or a playlist having many
|
8
11
|
songs. Some file attachment libraries provide a special interface for multiple
|
@@ -67,8 +70,9 @@ files (or attachments) table will be the photos table.
|
|
67
70
|
Let's create a table for the main resource and attachments, and add a foreign
|
68
71
|
key in the attachment table for the main table:
|
69
72
|
|
70
|
-
|
71
|
-
|
73
|
+
<Tabs>
|
74
|
+
<TabItem value="sequel" label="Sequel">
|
75
|
+
|
72
76
|
```rb
|
73
77
|
Sequel.migration do
|
74
78
|
change do
|
@@ -87,7 +91,10 @@ Sequel.migration do
|
|
87
91
|
end
|
88
92
|
end
|
89
93
|
```
|
90
|
-
|
94
|
+
|
95
|
+
</TabItem>
|
96
|
+
<TabItem value="activerecord" label="Active Record">
|
97
|
+
|
91
98
|
```rb
|
92
99
|
class CreateAlbumsAndPhotos < ActiveRecord::Migration
|
93
100
|
def change
|
@@ -104,25 +111,33 @@ class CreateAlbumsAndPhotos < ActiveRecord::Migration
|
|
104
111
|
end
|
105
112
|
end
|
106
113
|
```
|
107
|
-
|
114
|
+
|
115
|
+
</TabItem>
|
116
|
+
</Tabs>
|
108
117
|
|
109
118
|
In the Photo model, create a Shrine attachment attribute named `image`
|
110
119
|
(`:image` matches the `_data` column prefix above):
|
111
120
|
|
112
|
-
|
113
|
-
|
121
|
+
<Tabs>
|
122
|
+
<TabItem value="sequel" label="Sequel">
|
123
|
+
|
114
124
|
```rb
|
115
125
|
class Photo < Sequel::Model
|
116
126
|
include ImageUploader::Attachment(:image)
|
117
127
|
end
|
118
128
|
```
|
119
|
-
|
129
|
+
|
130
|
+
</TabItem>
|
131
|
+
<TabItem value="activerecord" label="Active Record">
|
132
|
+
|
120
133
|
```rb
|
121
134
|
class Photo < ActiveRecord::Base
|
122
135
|
include ImageUploader::Attachment(:image)
|
123
136
|
end
|
124
137
|
```
|
125
|
-
|
138
|
+
|
139
|
+
</TabItem>
|
140
|
+
</Tabs>
|
126
141
|
|
127
142
|
### 2. Declare nested attributes
|
128
143
|
|
@@ -131,8 +146,9 @@ Using nested attributes is the easiest way to implement any dynamic
|
|
131
146
|
relationship to the photos table, and allow it to directly accept attributes
|
132
147
|
for the associated photo records by enabling nested attributes:
|
133
148
|
|
134
|
-
|
135
|
-
|
149
|
+
<Tabs>
|
150
|
+
<TabItem value="sequel" label="Sequel">
|
151
|
+
|
136
152
|
```rb
|
137
153
|
class Album < Sequel::Model
|
138
154
|
one_to_many :photos
|
@@ -142,14 +158,20 @@ class Album < Sequel::Model
|
|
142
158
|
nested_attributes :photos, destroy: true
|
143
159
|
end
|
144
160
|
```
|
145
|
-
|
161
|
+
|
162
|
+
</TabItem>
|
163
|
+
<TabItem value="activerecord" label="Active Record">
|
164
|
+
|
146
165
|
```rb
|
147
166
|
class Album < ActiveRecord::Base
|
148
167
|
has_many :photos, dependent: :destroy
|
149
168
|
accepts_nested_attributes_for :photos, allow_destroy: true
|
150
169
|
end
|
151
170
|
```
|
152
|
-
|
171
|
+
|
172
|
+
</TabItem>
|
173
|
+
<TabItem value="mongoid" label="Mongoid">
|
174
|
+
|
153
175
|
```rb
|
154
176
|
class Album
|
155
177
|
include Mongoid::Document
|
@@ -157,7 +179,9 @@ class Album
|
|
157
179
|
accepts_nested_attributes_for :photos
|
158
180
|
end
|
159
181
|
```
|
160
|
-
|
182
|
+
|
183
|
+
</TabItem>
|
184
|
+
</Tabs>
|
161
185
|
|
162
186
|
Documentation on nested attributes:
|
163
187
|
|
@@ -174,13 +198,14 @@ already created photos, so that the same form can be used for updating the
|
|
174
198
|
album/photos as well (they will be submitted under the
|
175
199
|
`album[photos_attributes]` parameter).
|
176
200
|
|
177
|
-
|
178
|
-
|
201
|
+
<Tabs>
|
202
|
+
<TabItem value="rails" label="Rails form builder">
|
203
|
+
|
179
204
|
```rb
|
180
205
|
form_for @album, html: { enctype: "multipart/form-data" } do |f|
|
181
206
|
f.text_field :title
|
182
207
|
f.fields_for :photos do |p| # adds new `album[photos_attributes]` parameter
|
183
|
-
p.hidden_field :image, value: p.object.cached_image_data
|
208
|
+
p.hidden_field :image, value: p.object.cached_image_data, id: nil
|
184
209
|
p.file_field :image
|
185
210
|
p.check_box :_destroy unless p.object.new_record?
|
186
211
|
end
|
@@ -188,7 +213,10 @@ form_for @album, html: { enctype: "multipart/form-data" } do |f|
|
|
188
213
|
f.submit "Create"
|
189
214
|
end
|
190
215
|
```
|
191
|
-
|
216
|
+
|
217
|
+
</TabItem>
|
218
|
+
<TabItem value="forme" label="Forme">
|
219
|
+
|
192
220
|
```rb
|
193
221
|
form @album, action: "/photos", enctype: "multipart/form-data" do |f|
|
194
222
|
f.input :title
|
@@ -201,7 +229,9 @@ form @album, action: "/photos", enctype: "multipart/form-data" do |f|
|
|
201
229
|
f.button "Create"
|
202
230
|
end
|
203
231
|
```
|
204
|
-
|
232
|
+
|
233
|
+
</TabItem>
|
234
|
+
</Tabs>
|
205
235
|
|
206
236
|
In your controller you should still be able to assign all the attributes to the
|
207
237
|
album, just remember to whitelist the new parameter for the nested attributes,
|
@@ -286,21 +316,26 @@ class ImageUploader < Shrine
|
|
286
316
|
end
|
287
317
|
end
|
288
318
|
```
|
289
|
-
|
290
|
-
|
319
|
+
<Tabs>
|
320
|
+
<TabItem value="sequel" label="Sequel">
|
321
|
+
|
291
322
|
```rb
|
292
323
|
class Album < Sequel::Model
|
293
324
|
# ... (nested_attributes already enables validating associated photos) ...
|
294
325
|
end
|
295
326
|
```
|
296
|
-
|
327
|
+
|
328
|
+
</TabItem>
|
329
|
+
<TabItem value="activerecord" label="Active Record">
|
330
|
+
|
297
331
|
```rb
|
298
332
|
class Album < ActiveRecord::Base
|
299
333
|
# ...
|
300
334
|
validates_associated :photos
|
301
335
|
end
|
302
336
|
```
|
303
|
-
|
337
|
+
</TabItem>
|
338
|
+
</Tabs>
|
304
339
|
|
305
340
|
Note that by default only metadata set on the client side will be available for
|
306
341
|
validations. Shrine will not automatically run metadata extraction for directly
|
data/doc/paperclip.md
CHANGED
@@ -695,6 +695,7 @@ s3.upload(io, "object/destination/path")
|
|
695
695
|
The Shrine storage has no replacement for the `:url` Paperclip option, and it
|
696
696
|
isn't needed.
|
697
697
|
|
698
|
+
[metadata_attributes]: https://shrinerb.com/docs/plugins/metadata_attributes
|
698
699
|
[Managing Derivatives]: https://shrinerb.com/docs/changing-derivatives
|
699
700
|
[direct uploads]: https://shrinerb.com/docs/getting-started#direct-uploads
|
700
701
|
[S3]: https://shrinerb.com/docs/storage/s3
|
@@ -46,7 +46,7 @@ Then, in your initializer, you can configure all uploaders to use these jobs:
|
|
46
46
|
|
47
47
|
```rb
|
48
48
|
Shrine::Attacher.promote_block do
|
49
|
-
PromoteJob.perform_async(self.class.name, record.class.name, record.id, name, file_data)
|
49
|
+
PromoteJob.perform_async(self.class.name, record.class.name, record.id, name.to_s, file_data)
|
50
50
|
end
|
51
51
|
Shrine::Attacher.destroy_block do
|
52
52
|
DestroyJob.perform_async(self.class.name, data)
|
@@ -58,7 +58,7 @@ Alternatively, you can setup backgrounding only for specific uploaders:
|
|
58
58
|
```rb
|
59
59
|
class MyUploader < Shrine
|
60
60
|
Attacher.promote_block do
|
61
|
-
PromoteJob.perform_async(self.class.name, record.class.name, record.id, name, file_data)
|
61
|
+
PromoteJob.perform_async(self.class.name, record.class.name, record.id, name.to_s, file_data)
|
62
62
|
end
|
63
63
|
Attacher.destroy_block do
|
64
64
|
DestroyJob.perform_async(self.class.name, data)
|
@@ -121,7 +121,7 @@ Shrine::Attacher.promote_block do |attacher|
|
|
121
121
|
attacher.class.name,
|
122
122
|
attacher.record.class.name,
|
123
123
|
attacher.record.id,
|
124
|
-
attacher.name,
|
124
|
+
attacher.name.to_s,
|
125
125
|
attacher.file_data,
|
126
126
|
)
|
127
127
|
end
|
@@ -143,7 +143,7 @@ photo.image_attacher.promote_block do |attacher|
|
|
143
143
|
attacher.class.name,
|
144
144
|
attacher.record.class.name,
|
145
145
|
attacher.record.id,
|
146
|
-
attacher.name,
|
146
|
+
attacher.name.to_s,
|
147
147
|
attacher.file_data,
|
148
148
|
current_user.id, # pass arguments known at the controller level
|
149
149
|
)
|
@@ -331,6 +331,29 @@ uploaded_file.derivation_url(:thumbnail, expires_in: 90)
|
|
331
331
|
#=> ".../thumbnail/eyJpZCI6ImZvbyIsInN?expires_at=1547843568&signature=..."
|
332
332
|
```
|
333
333
|
|
334
|
+
## Custom signer
|
335
|
+
|
336
|
+
The derivation URLs are signed by default, and the signature is checked when
|
337
|
+
the URLs are requested, which prevents tampering. If you have URL expiration
|
338
|
+
turned on, this may prevent your CDN from caching the response.
|
339
|
+
|
340
|
+
In this case, you may need to do custom CDN-specific URL signing. You can
|
341
|
+
bypass Shrine's default signing by passing a custom signer:
|
342
|
+
|
343
|
+
```rb
|
344
|
+
require "aws-sdk-cloudfront"
|
345
|
+
signer = Aws::CloudFront::UrlSigner.new(key_pair_id: "...", private_key: "...")
|
346
|
+
|
347
|
+
plugin :derivation_endpoint,
|
348
|
+
expires_in: 90,
|
349
|
+
signer: -> (url, expires_in:) do
|
350
|
+
signer.signed_url(url, expires: Time.now.to_i + expires_in)
|
351
|
+
end
|
352
|
+
```
|
353
|
+
|
354
|
+
When `:signer` option is used, the `:secret_key` option is not required, as
|
355
|
+
that secret is only used for default signing.
|
356
|
+
|
334
357
|
## Response headers
|
335
358
|
|
336
359
|
### Content Type
|
@@ -796,6 +819,7 @@ derivation.option(:upload_location)
|
|
796
819
|
| `:metadata` | List of metadata keys the source uploaded file should include in the derivation block | `[]` |
|
797
820
|
| `:prefix` | Path prefix added to the URLs | `nil` |
|
798
821
|
| `:secret_key` | Key used to sign derivation URLs in order to prevent tampering | required |
|
822
|
+
| `:signer` | Proc accepting URL and query params used for custom signing of URLs. | `nil` |
|
799
823
|
| `:type` | Media type returned in the `Content-Type` response header in the derivation response | determined from derivative's extension when possible |
|
800
824
|
| `:upload` | Whether the generated derivatives will be cached on the storage | `false` |
|
801
825
|
| `:upload_location` | Location to which the derivatives will be uploaded on the storage | `<source id>/<name>-<args>` |
|
data/doc/plugins/derivatives.md
CHANGED
@@ -133,7 +133,7 @@ Attacher.default_url do |derivative: nil, **|
|
|
133
133
|
end
|
134
134
|
```
|
135
135
|
```rb
|
136
|
-
photo.image_url(:medium) #=> "https://example.com/fallbacks
|
136
|
+
photo.image_url(:medium) #=> "https://example.com/fallbacks/medium.jpg"
|
137
137
|
```
|
138
138
|
|
139
139
|
Any additional URL options passed to `#<name>_url` will be forwarded to the
|
@@ -778,6 +778,16 @@ derivatives #=>
|
|
778
778
|
Like `Shrine.uploaded_file`, the `Shrine.derivatives` method accepts data as a
|
779
779
|
hash (stringified or symbolized) or a JSON string.
|
780
780
|
|
781
|
+
### Marshalling
|
782
|
+
|
783
|
+
The `Attacher` instance uses a mutex to make `Attacher#merge_derivatives`
|
784
|
+
thread-safe, which is not marshallable. If you want to be able to marshal the
|
785
|
+
attacher instance, you can skip mutex usage:
|
786
|
+
|
787
|
+
```rb
|
788
|
+
plugin :derivatives, mutex: false
|
789
|
+
```
|
790
|
+
|
781
791
|
## Instrumentation
|
782
792
|
|
783
793
|
If the `instrumentation` plugin has been loaded, the `derivatives` plugin adds
|
data/doc/plugins/entity.md
CHANGED
@@ -22,7 +22,9 @@ These methods read attachment data from the `#<name>_data` attribute on the
|
|
22
22
|
entity instance.
|
23
23
|
|
24
24
|
```rb
|
25
|
-
class Photo
|
25
|
+
class Photo
|
26
|
+
attr_reader :image_data
|
27
|
+
|
26
28
|
include ImageUploader::Attachment(:image)
|
27
29
|
end
|
28
30
|
```
|
@@ -94,7 +96,9 @@ You can also specify default attacher options when including
|
|
94
96
|
`Shrine::Attachment`:
|
95
97
|
|
96
98
|
```rb
|
97
|
-
class Photo
|
99
|
+
class Photo
|
100
|
+
attr_reader :image_data
|
101
|
+
|
98
102
|
include ImageUploader::Attachment(:image, store: :other_store)
|
99
103
|
end
|
100
104
|
```
|
@@ -123,7 +127,8 @@ You can also use `Shrine::Attacher` directly (with or without the
|
|
123
127
|
`Shrine::Attachment` module):
|
124
128
|
|
125
129
|
```rb
|
126
|
-
class Photo
|
130
|
+
class Photo
|
131
|
+
attr_reader :image_data
|
127
132
|
end
|
128
133
|
```
|
129
134
|
```rb
|
@@ -191,7 +196,7 @@ attacher.file #=> nil
|
|
191
196
|
### Reloading
|
192
197
|
|
193
198
|
The `Attacher#reload` method reloads attached file from the attachment data on
|
194
|
-
the entity attribute.
|
199
|
+
the entity attribute and resets dirty tracking.
|
195
200
|
|
196
201
|
```rb
|
197
202
|
photo = Photo.new
|
@@ -206,6 +211,9 @@ attacher.reload
|
|
206
211
|
attacher.file #=> #<ImageUploader::UploadedFile>
|
207
212
|
```
|
208
213
|
|
214
|
+
If you want to reload attachment data while retaining dirty tracking state, use
|
215
|
+
`Attacher#read` instead.
|
216
|
+
|
209
217
|
### Column values
|
210
218
|
|
211
219
|
The `Attacher#column_values` method returns a hash with the entity attribute as
|
data/doc/plugins/keep_files.md
CHANGED
@@ -2,10 +2,11 @@
|
|
2
2
|
title: Keep Files
|
3
3
|
---
|
4
4
|
|
5
|
-
The [`keep_files`][keep_files] plugin prevents file
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
The [`keep_files`][keep_files] plugin prevents the attached file (and any of
|
6
|
+
its [derivatives]) from being deleted when the attachment would normally be
|
7
|
+
destroyed, which happens when the attachment is removed/replaced, or when the
|
8
|
+
record is deleted. This functionality is useful when implementing soft deletes,
|
9
|
+
versioning, or in general any scenario where you need to keep history.
|
9
10
|
|
10
11
|
```rb
|
11
12
|
plugin :keep_files
|
@@ -17,3 +18,4 @@ photo.image.exists? #=> true
|
|
17
18
|
```
|
18
19
|
|
19
20
|
[keep_files]: https://github.com/shrinerb/shrine/blob/master/lib/shrine/plugins/keep_files.rb
|
21
|
+
[derivatives]: https://shrinerb.com/docs/plugins/derivatives
|
data/doc/plugins/model.md
CHANGED
@@ -17,7 +17,9 @@ Including a `Shrine::Attachment` module into a model class will:
|
|
17
17
|
* add `#<name>=` and `#<name>_changed?` methods
|
18
18
|
|
19
19
|
```rb
|
20
|
-
class Photo
|
20
|
+
class Photo
|
21
|
+
attr_accessor :image_data
|
22
|
+
|
21
23
|
include ImageUploader::Attachment(:image)
|
22
24
|
end
|
23
25
|
```
|
@@ -107,7 +109,9 @@ If you still want to include `Shrine::Attachment` modules to immutable
|
|
107
109
|
entities, you can disable "model" behaviour by passing `model: false`:
|
108
110
|
|
109
111
|
```rb
|
110
|
-
class Photo
|
112
|
+
class Photo
|
113
|
+
attr_reader :image_data
|
114
|
+
|
111
115
|
include ImageUploader::Attachment(:image, model: false)
|
112
116
|
end
|
113
117
|
```
|
@@ -118,7 +122,8 @@ You can also use `Shrine::Attacher` directly (with or without the
|
|
118
122
|
`Shrine::Attachment` module):
|
119
123
|
|
120
124
|
```rb
|
121
|
-
class Photo
|
125
|
+
class Photo
|
126
|
+
attr_accessor :image_data
|
122
127
|
end
|
123
128
|
```
|
124
129
|
```rb
|
data/doc/plugins/sequel.md
CHANGED
@@ -172,7 +172,7 @@ attacher.file #=> #<Shrine::UploadedFile id="397eca.jpg" storage=:store ...>
|
|
172
172
|
photo.image_data #=> '{"id":"397eca.jpg","storage":"store","metadata":{...}}'
|
173
173
|
```
|
174
174
|
|
175
|
-
###
|
175
|
+
### Persistence
|
176
176
|
|
177
177
|
The following persistence methods are added to `Shrine::Attacher`:
|
178
178
|
|
data/doc/processing.md
CHANGED
@@ -315,14 +315,15 @@ previews.
|
|
315
315
|
|
316
316
|
Shrine provides on-the-fly processing functionality via the
|
317
317
|
**[`derivation_endpoint`][derivation_endpoint]** plugin. You set it up by
|
318
|
-
loading the plugin with a secret key
|
318
|
+
loading the plugin with a secret key (you generate this yourself, maybe via
|
319
|
+
something like `SecureRandom.hex`) and a path prefix, mount its Rack app in
|
319
320
|
your routes on the configured path prefix, and define processing you want to
|
320
321
|
perform:
|
321
322
|
|
322
323
|
```rb
|
323
324
|
# config/initializers/shrine.rb (Rails)
|
324
325
|
# ...
|
325
|
-
Shrine.plugin :
|
326
|
+
Shrine.plugin :derivation_endpoint, secret_key: "<SHRINE_SECRET_KEY>"
|
326
327
|
```
|
327
328
|
```rb
|
328
329
|
require "image_processing/mini_magick"
|
data/doc/refile.md
CHANGED
@@ -458,7 +458,7 @@ Shrine.plugin :cached_attachment_data
|
|
458
458
|
```
|
459
459
|
```rb
|
460
460
|
form_for @user do |form|
|
461
|
-
form.hidden_field :profile_image, value: @user.cached_profile_image_data
|
461
|
+
form.hidden_field :profile_image, value: @user.cached_profile_image_data, id: nil
|
462
462
|
form.file_field :profile_image
|
463
463
|
end
|
464
464
|
```
|
@@ -475,7 +475,7 @@ Shrine.plugin :remove_attachment
|
|
475
475
|
```
|
476
476
|
```rb
|
477
477
|
form_for @user do |form|
|
478
|
-
form.hidden_field :profile_image, value: @user.cached_profile_image_data
|
478
|
+
form.hidden_field :profile_image, value: @user.cached_profile_image_data, id: nil
|
479
479
|
form.file_field :profile_image
|
480
480
|
form.check_box :remove_profile_image
|
481
481
|
end
|
@@ -491,7 +491,7 @@ Shrine.plugin :remote_url
|
|
491
491
|
```
|
492
492
|
```rb
|
493
493
|
form_for @user do |form|
|
494
|
-
form.hidden_field :profile_image, value: @user.cached_profile_image_data
|
494
|
+
form.hidden_field :profile_image, value: @user.cached_profile_image_data, id: nil
|
495
495
|
form.file_field :profile_image
|
496
496
|
form.text_field :profile_image_remote_url
|
497
497
|
end
|
data/doc/release_notes/2.1.0.md
CHANGED
@@ -0,0 +1,35 @@
|
|
1
|
+
---
|
2
|
+
title: Shrine 3.4.0
|
3
|
+
---
|
4
|
+
|
5
|
+
* Passing attacher options to `Shrine.Attachment` method now works on Ruby 3.0.
|
6
|
+
|
7
|
+
* Defining validation errors as an array of I18n key and options in
|
8
|
+
`activerecord` plugin now works on Ruby 3.0.
|
9
|
+
|
10
|
+
* The `:fastimage` MIME type analyzer now correctly detects SVGs as
|
11
|
+
`image/svg+html` in the `determine_mime_type` plugin.
|
12
|
+
|
13
|
+
* The `Shrine::Attacher#read` method provided by the `entity` plugin is now
|
14
|
+
public. This is consistent with `Shrine::Attacher#write` from `model` plugin
|
15
|
+
being public as well.
|
16
|
+
|
17
|
+
* The `Shrine::Attacher#reload` method now resets attachment's dirty state.
|
18
|
+
This means that for a model whose `Attacher#changed?` returns `true`, calling
|
19
|
+
`#reload` on the model will make `Attacher#changed?` return `false`. This was
|
20
|
+
the behaviour before Shrine 3.3.0.
|
21
|
+
|
22
|
+
```rb
|
23
|
+
# before
|
24
|
+
model.file_attacher.changed? #=> true
|
25
|
+
model.reload
|
26
|
+
model.file_attacher.changed? #=> true
|
27
|
+
|
28
|
+
# after
|
29
|
+
model.file_attacher.changed? #=> true
|
30
|
+
model.reload
|
31
|
+
model.file_attacher.changed? #=> false
|
32
|
+
```
|
33
|
+
|
34
|
+
* Calling `#reload` on the model will not initialize a `Shrine::Attacher`
|
35
|
+
instance anymore if one hasn't previously been initialized.
|
@@ -0,0 +1,63 @@
|
|
1
|
+
---
|
2
|
+
title: Shrine 3.5.0
|
3
|
+
---
|
4
|
+
|
5
|
+
## New features
|
6
|
+
|
7
|
+
* The website has been migrated to Docusaurus v2. :sparkles:
|
8
|
+
|
9
|
+
* The `:signer` option has been added to the `derivation_endpoint` plugin, for when you want to use custom URL signing. This is useful when using `:expires_in`, and wanting to have expiring URLs work with CDN caching.
|
10
|
+
|
11
|
+
```rb
|
12
|
+
require "aws-sdk-cloudfront"
|
13
|
+
signer = Aws::CloudFront::UrlSigner.new(key_pair_id: "...", private_key: "...")
|
14
|
+
|
15
|
+
plugin :derivation_endpoint,
|
16
|
+
expires_in: 90,
|
17
|
+
signer: -> (url, expires_in:) do
|
18
|
+
signer.signed_url(url, expires: Time.now.to_i + expires_in)
|
19
|
+
end
|
20
|
+
```
|
21
|
+
|
22
|
+
* The S3 storage now supports `:max_multipart_parts` option for specifying the maximum number of concurrent parts in which a large file will get uploaded. This number defaults to `10_000`.
|
23
|
+
|
24
|
+
```rb
|
25
|
+
Shrine::Storage::S3.new(max_multipart_parts: 1000, ...)
|
26
|
+
```
|
27
|
+
|
28
|
+
* The `:encoding` option can now be passed to `S3#open`, which is applied to downloaded chunks.
|
29
|
+
|
30
|
+
```rb
|
31
|
+
io = uploaded_file.open(encoding: Encoding::UTF_8)
|
32
|
+
csv = CSV.new(io)
|
33
|
+
# ...
|
34
|
+
```
|
35
|
+
|
36
|
+
## Other improvements
|
37
|
+
|
38
|
+
* Passing a boolean value to the `#remove_attachment=` setter now works on Ruby 3.2. Previously this would raise an error, because Shrine would try to call `=~` on it, but `Object#=~` method has been removed in Ruby 3.2.
|
39
|
+
|
40
|
+
* When duplicating a model instance, the duplicated attacher now references the duplicated model instance instead of the original one.
|
41
|
+
|
42
|
+
* The download endpoint now returns a `400 Bad Request` response when the serialized file component is invalid.
|
43
|
+
|
44
|
+
* The `derivatives` plugin now supports passing `mutex: false` option to disable usage of a mutex. This makes the `Shrine::Attacher` object marshallable, which should enable using `Marshal.dump` and `Marshal.load` on model instances with attachments. This should be safe unless you're adding derivatives on the same attacher object concurrently.
|
45
|
+
|
46
|
+
* When loading the `derivatives` plugin with `versions_compatibility: true`, this setting doesn't leak to other uploaders anymore. Previously if other uploaders would load `derivatives` plugin without this option, versions compatibility would still get enabled for them. This change also fixes behavior on JRuby.
|
47
|
+
|
48
|
+
* When S3 storage copies files, the AWS tag are not inherited anymore. This allows passing the `:tagging` upload option when promoting from temporary to permanent storage, and have it take effect.
|
49
|
+
|
50
|
+
* The `UploadedFile#url` method doesn't call the obsolete `URI.regexp` method anymore, which should avoid warnings.
|
51
|
+
|
52
|
+
* The `infer_extension` plugin now defines `infer_extension` instance method (in addition to class method) on the uploader for convenience, so that it can be easily called at the uploader instance level.
|
53
|
+
|
54
|
+
```rb
|
55
|
+
class MyUploader < Shrine
|
56
|
+
plugin :infer_extension
|
57
|
+
|
58
|
+
def generate_location(io, metadata:, **)
|
59
|
+
extension = infer_extension(metadata["mime_type"])
|
60
|
+
# ...
|
61
|
+
end
|
62
|
+
end
|
63
|
+
```
|
data/doc/retrieving_uploads.md
CHANGED
@@ -124,7 +124,7 @@ end # underlying IO object is closed
|
|
124
124
|
```
|
125
125
|
|
126
126
|
`Shrine::UploadedFile#open` will return the result of a given block.
|
127
|
-
|
127
|
+
We can use that to safely retrieve the whole content of a file, without
|
128
128
|
leaving any temporary files lying around.
|
129
129
|
|
130
130
|
```rb
|