shrine 3.4.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 +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
|