shrine 3.4.0 → 3.5.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +26 -0
- data/README.md +11 -11
- data/doc/carrierwave.md +2 -2
- data/doc/changing_location.md +2 -1
- data/doc/external/articles.md +16 -16
- data/doc/external/extensions.md +1 -1
- data/doc/getting_started.md +69 -28
- data/doc/multiple_files.md +57 -22
- 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/keep_files.md +6 -4
- data/doc/plugins/validation_helpers.md +1 -1
- data/doc/refile.md +3 -3
- data/doc/release_notes/2.1.0.md +1 -1
- data/doc/release_notes/3.5.0.md +63 -0
- data/doc/retrieving_uploads.md +1 -1
- data/doc/testing.md +45 -17
- data/doc/upgrading_to_3.md +3 -5
- data/lib/shrine/plugins/derivation_endpoint.rb +30 -29
- data/lib/shrine/plugins/derivatives.rb +23 -15
- data/lib/shrine/plugins/download_endpoint.rb +7 -0
- data/lib/shrine/plugins/entity.rb +8 -2
- data/lib/shrine/plugins/infer_extension.rb +4 -0
- data/lib/shrine/plugins/instrumentation.rb +5 -1
- data/lib/shrine/plugins/model.rb +3 -1
- data/lib/shrine/plugins/remove_attachment.rb +2 -0
- 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 +1 -1
- data/shrine.gemspec +2 -2
- metadata +8 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 46e9fa07aa69797777e3072eed12a4b901b357ae840c71f4facd5b0be2d79929
|
4
|
+
data.tar.gz: 0714e663dd130b9af96b195e5a3d87c128a0e6dd0b0598a7b2d4286e97223008
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 87b70c2bd15dd044eacc1b2089b65bb0538728fd56dea5cce8e6e191b3bf07e63e2af45b877bfd317bcf38c98279c49d07f5d18db28d106cb08360478f1bcb76
|
7
|
+
data.tar.gz: 57703469c6efa1e724113944815dc9fb5e2a3506cf261810c07d0e40c7849bc79d2184bb576222ca7a21c56fe3f496602e93d7b60696cee763aabdaaed71cf23
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,29 @@
|
|
1
|
+
## 3.5.0 (2023-07-06)
|
2
|
+
|
3
|
+
* Migrate website to Docusaurus v2 (@janko)
|
4
|
+
|
5
|
+
* `download_endpoint` – Return `400 Bad Request` response when serialized file component is invalid (@janko)
|
6
|
+
|
7
|
+
* `base` – Stop using obsolete `URI.regexp` in `UploadedFile#extension` (@y-yagi)
|
8
|
+
|
9
|
+
* `s3` – Add `:encoding` option to `S3#open` to be passed to `Down::ChunkedIO#initialize` (@pond)
|
10
|
+
|
11
|
+
* `s3` – Add `:max_multipart_parts` option for changing default limit of 10,000 parts (@jpl)
|
12
|
+
|
13
|
+
* `s3` – Don't inherit S3 object tags when copying from temporary to permanent storage (@jrochkind)
|
14
|
+
|
15
|
+
* `infer_extension` – Add `infer_extension` instance method to the uploader for convenience (@aried3r)
|
16
|
+
|
17
|
+
* `derivation_endpoint` – Add `:signer` plugin option for providing a custom URL signer (@thibaudgg)
|
18
|
+
|
19
|
+
* `derivatives` – Don't leak `versions_compatibility: true` setting into other uploaders (@janko)
|
20
|
+
|
21
|
+
* `derivatives` – Add `:mutex` plugin option for skipping mutex and making attacher marshallable (@janko)
|
22
|
+
|
23
|
+
* `remove_attachment` – Fix passing boolean values being broken in Ruby 3.2 (@janko)
|
24
|
+
|
25
|
+
* `model` – When duplicating a record, make the duplicated attacher reference the duplicated record (@janko)
|
26
|
+
|
1
27
|
## 3.4.0 (2021-06-14)
|
2
28
|
|
3
29
|
* `base` – Fix passing options to `Shrine.Attachment` on Ruby 3.0 (@lucianghinda)
|
data/README.md
CHANGED
@@ -20,20 +20,20 @@ guide]**.
|
|
20
20
|
|
21
21
|
## Links
|
22
22
|
|
23
|
-
| Resource
|
24
|
-
| :----------------
|
25
|
-
| Website & Documentation
|
26
|
-
| Demo code
|
27
|
-
| Wiki
|
28
|
-
|
|
23
|
+
| Resource | URL |
|
24
|
+
| :---------------- | :----------------------------------------------------------------------------- |
|
25
|
+
| Website & Documentation | [shrinerb.com](https://shrinerb.com) |
|
26
|
+
| Demo code | [Roda][roda demo] / [Rails][rails demo] |
|
27
|
+
| Wiki | [github.com/shrinerb/shrine/wiki](https://github.com/shrinerb/shrine/wiki) |
|
28
|
+
| Discussion forum | [github.com/shrinerb/shrine/discussions](https://github.com/shrinerb/shrine/discussions) |
|
29
|
+
| Alternate Discussion forum | [discourse.shrinerb.com](https://discourse.shrinerb.com) |
|
29
30
|
|
30
31
|
## Setup
|
31
32
|
|
32
|
-
|
33
|
+
Run:
|
33
34
|
|
34
|
-
```
|
35
|
-
|
36
|
-
gem "shrine", "~> 3.0"
|
35
|
+
```sh
|
36
|
+
bundle add shrine
|
37
37
|
```
|
38
38
|
|
39
39
|
Then add `config/initializers/shrine.rb` which sets up the storage and loads
|
@@ -80,7 +80,7 @@ allow users to upload files:
|
|
80
80
|
|
81
81
|
```erb
|
82
82
|
<%= form_for @photo do |f| %>
|
83
|
-
<%= f.hidden_field :image, value: @photo.cached_image_data %>
|
83
|
+
<%= f.hidden_field :image, value: @photo.cached_image_data, id: nil %>
|
84
84
|
<%= f.file_field :image %>
|
85
85
|
<%= f.submit %>
|
86
86
|
<% end %>
|
data/doc/carrierwave.md
CHANGED
@@ -368,7 +368,7 @@ Now you should be able to rewrite your application so that it uses Shrine
|
|
368
368
|
instead of CarrierWave (you can consult the reference in the next section). You
|
369
369
|
can remove the `CarrierwaveShrineSynchronization` module as well.
|
370
370
|
|
371
|
-
### 5.
|
371
|
+
### 5. Backfill metadata
|
372
372
|
|
373
373
|
You'll notice that Shrine metadata will be absent from the migrated files'
|
374
374
|
data. You can run a script that will fill in any missing metadata defined in
|
@@ -646,7 +646,7 @@ Shrine.plugin :cached_attachment_data
|
|
646
646
|
```
|
647
647
|
```rb
|
648
648
|
form_for @photo do |f|
|
649
|
-
f.hidden_field :image, value: @photo.cached_image_data
|
649
|
+
f.hidden_field :image, value: @photo.cached_image_data, id: nil
|
650
650
|
f.file_field :image
|
651
651
|
end
|
652
652
|
```
|
data/doc/changing_location.md
CHANGED
@@ -99,11 +99,12 @@ class MoveFilesJob
|
|
99
99
|
|
100
100
|
attacher = attacher_class.retrieve(model: record, name: name, file: file_data)
|
101
101
|
old_attacher = attacher.dup
|
102
|
+
current_file = old_attacher.file
|
102
103
|
|
103
104
|
attacher.set attacher.upload(attacher.file)
|
104
105
|
attacher.set_derivatives attacher.upload_derivatives(attacher.derivatives)
|
105
106
|
|
106
|
-
attacher.atomic_persist
|
107
|
+
attacher.atomic_persist(current_file)
|
107
108
|
old_attacher.destroy_attached
|
108
109
|
rescue Shrine::AttachmentChanged, ActiveRecord::RecordNotFound
|
109
110
|
attacher&.destroy_attached
|
data/doc/external/articles.md
CHANGED
@@ -4,22 +4,22 @@ title: Articles
|
|
4
4
|
|
5
5
|
## Official articles
|
6
6
|
|
7
|
-
| Article
|
8
|
-
| :-------
|
9
|
-
| [Better File Uploads with Shrine: Eager Processing](https://
|
10
|
-
| [Shrine 3.0 Released](https://
|
11
|
-
| [Upcoming Features in Shrine 3.0](https://
|
12
|
-
| [Better File Uploads with Shrine: Direct Uploads](https://
|
13
|
-
| [Better File Uploads with Shrine: Metadata](https://
|
14
|
-
| [Better File Uploads with Shrine: Processing](https://
|
15
|
-
| [Better File Uploads with Shrine: Attachment](https://
|
16
|
-
| [Better File Uploads with Shrine: Uploader](https://
|
17
|
-
| [Better File Uploads with Shrine: Motivation](https://
|
18
|
-
| [Resumable File Uploads in Ruby](https://
|
19
|
-
| [Shrine meets Transloadit](https://
|
20
|
-
| [Shrine 2.0 Released](https://
|
21
|
-
| [Asynchronous File Uploads](http://
|
22
|
-
| [Introducing Shrine](http://
|
7
|
+
| Article | Published |
|
8
|
+
| :------- | --------: |
|
9
|
+
| [Better File Uploads with Shrine: Eager Processing](https://janko.io/better-file-uploads-with-shrine-eager-processing/) | 12 Dec 2019 |
|
10
|
+
| [Shrine 3.0 Released](https://janko.io/shrine-3-0-released/) | 14 Oct 2019 |
|
11
|
+
| [Upcoming Features in Shrine 3.0](https://janko.io/upcoming-features-in-shrine-3-0/) | 29 Aug 2019 |
|
12
|
+
| [Better File Uploads with Shrine: Direct Uploads](https://janko.io/better-file-uploads-with-shrine-direct-uploads/) | 08 Jan 2018 |
|
13
|
+
| [Better File Uploads with Shrine: Metadata](https://janko.io/better-file-uploads-with-shrine-metadata/) | 07 Nov 2016 |
|
14
|
+
| [Better File Uploads with Shrine: Processing](https://janko.io/better-file-uploads-with-shrine-processing/) | 31 Oct 2016 |
|
15
|
+
| [Better File Uploads with Shrine: Attachment](https://janko.io/better-file-uploads-with-shrine-attachment/) | 17 Sep 2016 |
|
16
|
+
| [Better File Uploads with Shrine: Uploader](https://janko.io/better-file-uploads-with-shrine-uploader/) | 16 Sep 2016 |
|
17
|
+
| [Better File Uploads with Shrine: Motivation](https://janko.io/better-file-uploads-with-shrine-motivation/) | 11 Sep 2016 |
|
18
|
+
| [Resumable File Uploads in Ruby](https://janko.io/resumable-file-uploads-in-ruby/) | 04 Sep 2016 |
|
19
|
+
| [Shrine meets Transloadit](https://janko.io/shrine-meets-transloadit/) | 11 Jul 2016 |
|
20
|
+
| [Shrine 2.0 Released](https://janko.io/shrine-2-0-released/) | 20 May 2016 |
|
21
|
+
| [Asynchronous File Uploads](http://janko.io/file-uploads-asynchronous-world) | 18 Jan 2016 |
|
22
|
+
| [Introducing Shrine](http://janko.io/introducing-shrine) | 04 Oct 2015 |
|
23
23
|
|
24
24
|
## Community articles
|
25
25
|
|
data/doc/external/extensions.md
CHANGED
@@ -35,7 +35,7 @@ title: Extensions
|
|
35
35
|
| [shrine-content_addressable](https://github.com/SleeplessByte/shrine-content_addressable) | Plugin for generating content addressable locations |
|
36
36
|
| [shrine-imgix](https://github.com/shrinerb/shrine-imgix) | Plugin for [Imgix](https://www.imgix.com/) |
|
37
37
|
| [shrine-transloadit](https://github.com/shrinerb/shrine-transloadit) | Plugin for [Transloadit](https://transloadit.com/) |
|
38
|
-
| [shrine-lambda](https://github.com/texpert/shrine-lambda)
|
38
|
+
| [shrine-aws-lambda](https://github.com/texpert/shrine-aws-lambda) | Plugin for [AWS Lambda](https://aws.amazon.com/lambda/) |
|
39
39
|
| [hanami-shrine](https://github.com/katafrakt/hanami-shrine) | Plugin for [Hanami](https://hanamirb.org/) |
|
40
40
|
| [shrine-mongoid](https://github.com/shrinerb/shrine-mongoid) | Plugin for [Mongoid](https://mongoid.org) |
|
41
41
|
| [shrine-rails](https://github.com/abepetrillo/shrine-rails) | Plugin for [Rails](https://rubyonrails.org/) |
|
data/doc/getting_started.md
CHANGED
@@ -3,6 +3,9 @@ id: getting-started
|
|
3
3
|
title: Getting Started
|
4
4
|
---
|
5
5
|
|
6
|
+
import Tabs from '@theme/Tabs';
|
7
|
+
import TabItem from '@theme/TabItem';
|
8
|
+
|
6
9
|
## Quick start
|
7
10
|
|
8
11
|
Add Shrine to the Gemfile and write an initializer which sets up the storage
|
@@ -32,32 +35,39 @@ Next decide how you will name the attachment attribute on your model, and run a
|
|
32
35
|
migration that adds an `<attachment>_data` text or JSON column, which Shrine
|
33
36
|
will use to store all information about the attachment:
|
34
37
|
|
35
|
-
|
36
|
-
|
38
|
+
<Tabs>
|
39
|
+
<TabItem value="sequel" label="Sequel">
|
40
|
+
|
37
41
|
```rb
|
38
42
|
Sequel.migration do
|
39
43
|
change do
|
40
|
-
add_column :photos, :image_data, :text # or :jsonb
|
44
|
+
add_column :photos, :image_data, :text # or :jsonb
|
41
45
|
end
|
42
46
|
end
|
43
47
|
```
|
44
48
|
|
45
|
-
|
49
|
+
</TabItem>
|
50
|
+
<TabItem value="activerecord" label="Active Record">
|
51
|
+
|
46
52
|
```rb
|
47
53
|
class AddImageDataToPhotos < ActiveRecord::Migration
|
48
54
|
def change
|
49
|
-
add_column :photos, :image_data, :text # or :jsonb
|
55
|
+
add_column :photos, :image_data, :text # or :jsonb
|
50
56
|
end
|
51
57
|
end
|
52
58
|
```
|
53
59
|
|
54
|
-
|
60
|
+
</TabItem>
|
61
|
+
<TabItem value="rails" label="Rails">
|
62
|
+
|
55
63
|
```rb
|
56
|
-
$ rails generate migration add_image_data_to_photos image_data:text
|
64
|
+
$ rails generate migration add_image_data_to_photos image_data:text # or image_data:jsonb
|
57
65
|
```
|
58
|
-
If using `jsonb` consider adding a [gin index] for fast key-value pair searchability within `image_data`.
|
59
66
|
|
60
|
-
|
67
|
+
</TabItem>
|
68
|
+
</Tabs>
|
69
|
+
|
70
|
+
If using `jsonb` consider adding a [gin index] for fast key-value pair searchability within `image_data`.
|
61
71
|
|
62
72
|
Now you can create an uploader class for the type of files you want to upload,
|
63
73
|
and add a virtual attribute for handling attachments using this uploader to
|
@@ -69,36 +79,47 @@ class ImageUploader < Shrine
|
|
69
79
|
# plugins and uploading logic
|
70
80
|
end
|
71
81
|
```
|
72
|
-
|
73
|
-
|
82
|
+
|
83
|
+
<Tabs>
|
84
|
+
<TabItem value="sequel" label="Sequel">
|
85
|
+
|
74
86
|
```rb
|
75
87
|
class Photo < Sequel::Model
|
76
88
|
include ImageUploader::Attachment(:image) # adds an `image` virtual attribute
|
77
89
|
end
|
78
90
|
```
|
79
|
-
|
91
|
+
|
92
|
+
</TabItem>
|
93
|
+
<TabItem value="activerecord" label="Active Record">
|
94
|
+
|
80
95
|
```rb
|
81
96
|
class Photo < ActiveRecord::Base
|
82
97
|
include ImageUploader::Attachment(:image) # adds an `image` virtual attribute
|
83
98
|
end
|
84
99
|
```
|
85
|
-
|
100
|
+
|
101
|
+
</TabItem>
|
102
|
+
</Tabs>
|
86
103
|
|
87
104
|
Let's now add the form fields which will use this virtual attribute (NOT the
|
88
105
|
`<attachment>_data` column attribute). We need (1) a file field for choosing
|
89
106
|
files, and (2) a hidden field for retaining the uploaded file in case of
|
90
107
|
validation errors and for potential [direct uploads].
|
91
108
|
|
92
|
-
|
93
|
-
|
109
|
+
<Tabs>
|
110
|
+
<TabItem value="rails" label="Rails form builder">
|
111
|
+
|
94
112
|
```rb
|
95
113
|
form_for @photo do |f|
|
96
|
-
f.hidden_field :image, value: @photo.cached_image_data
|
114
|
+
f.hidden_field :image, value: @photo.cached_image_data, id: nil
|
97
115
|
f.file_field :image
|
98
116
|
f.submit
|
99
117
|
end
|
100
118
|
```
|
101
|
-
|
119
|
+
|
120
|
+
</TabItem>
|
121
|
+
<TabItem value="simple_form" label="Simple Form">
|
122
|
+
|
102
123
|
```rb
|
103
124
|
simple_form_for @photo do |f|
|
104
125
|
f.input :image, as: :hidden, input_html: { value: @photo.cached_image_data }
|
@@ -106,7 +127,10 @@ simple_form_for @photo do |f|
|
|
106
127
|
f.button :submit
|
107
128
|
end
|
108
129
|
```
|
109
|
-
|
130
|
+
|
131
|
+
</TabItem>
|
132
|
+
<TabItem value="form" label="Forme">
|
133
|
+
|
110
134
|
```rb
|
111
135
|
form @photo, action: "/photos", enctype: "multipart/form-data" do |f|
|
112
136
|
f.input :image, type: :hidden, value: @photo.cached_image_data
|
@@ -114,7 +138,10 @@ form @photo, action: "/photos", enctype: "multipart/form-data" do |f|
|
|
114
138
|
f.button "Create"
|
115
139
|
end
|
116
140
|
```
|
117
|
-
|
141
|
+
|
142
|
+
</TabItem>
|
143
|
+
<TabItem value="html" label="HTML">
|
144
|
+
|
118
145
|
```erb
|
119
146
|
<form action="/photos" method="post" enctype="multipart/form-data">
|
120
147
|
<input name="photo[image]" type="hidden" value="<%= @photo.cached_image_data %>" />
|
@@ -122,7 +149,9 @@ end
|
|
122
149
|
<input type="submit" value="Create" />
|
123
150
|
</form>
|
124
151
|
```
|
125
|
-
|
152
|
+
|
153
|
+
</TabItem>
|
154
|
+
</Tabs>
|
126
155
|
|
127
156
|
Note that the file field needs to go *after* the hidden field, so that
|
128
157
|
selecting a new file can always override the cached file in the hidden field.
|
@@ -133,8 +162,9 @@ will automatically generate this for you).
|
|
133
162
|
When the form is submitted, in your router/controller you can assign the file
|
134
163
|
from request params to the attachment attribute on the model.
|
135
164
|
|
136
|
-
|
137
|
-
|
165
|
+
<Tabs>
|
166
|
+
<TabItem value="rails" label="Rails">
|
167
|
+
|
138
168
|
```rb
|
139
169
|
class PhotosController < ApplicationController
|
140
170
|
def create
|
@@ -149,28 +179,39 @@ class PhotosController < ApplicationController
|
|
149
179
|
end
|
150
180
|
end
|
151
181
|
```
|
152
|
-
|
182
|
+
|
183
|
+
</TabItem>
|
184
|
+
<TabItem value="sinatra" label="Sinatra">
|
185
|
+
|
153
186
|
```rb
|
154
187
|
post "/photos" do
|
155
188
|
Photo.create(params[:photo])
|
156
189
|
# ...
|
157
190
|
end
|
158
191
|
```
|
159
|
-
|
192
|
+
|
193
|
+
</TabItem>
|
194
|
+
</Tabs>
|
160
195
|
|
161
196
|
Once a file is uploaded and attached to the record, you can retrieve a URL to
|
162
197
|
the uploaded file with `#<attachment>_url` and display it on the page:
|
163
198
|
|
164
|
-
|
165
|
-
|
199
|
+
<Tabs>
|
200
|
+
<TabItem value="rails" label="Rails">
|
201
|
+
|
166
202
|
```erb
|
167
203
|
<%= image_tag @photo.image_url %>
|
168
204
|
```
|
169
|
-
|
205
|
+
|
206
|
+
</TabItem>
|
207
|
+
<TabItem value="html" label="HTML">
|
208
|
+
|
170
209
|
```erb
|
171
210
|
<img src="<%= @photo.image_url %>" />
|
172
211
|
```
|
173
|
-
|
212
|
+
|
213
|
+
</TabItem>
|
214
|
+
</Tabs>
|
174
215
|
|
175
216
|
## Storage
|
176
217
|
|
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
|
@@ -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
|