shrine 3.1.0 → 3.2.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of shrine might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +18 -0
- data/README.md +3 -3
- data/doc/advantages.md +3 -3
- data/doc/carrierwave.md +17 -8
- data/doc/design.md +134 -85
- data/doc/external/articles.md +1 -0
- data/doc/external/extensions.md +38 -35
- data/doc/getting_started.md +135 -79
- data/doc/metadata.md +79 -43
- data/doc/paperclip.md +13 -4
- data/doc/plugins/add_metadata.md +92 -35
- data/doc/plugins/backgrounding.md +12 -2
- data/doc/plugins/default_url.md +3 -0
- data/doc/plugins/derivatives.md +35 -27
- data/doc/plugins/included.md +25 -5
- data/doc/plugins/remove_invalid.md +9 -1
- data/doc/plugins/type_predicates.md +96 -0
- data/doc/plugins/url_options.md +2 -2
- data/doc/plugins/validation.md +5 -4
- data/doc/processing.md +286 -121
- data/doc/refile.md +9 -9
- data/doc/release_notes/3.2.0.md +96 -0
- data/doc/securing_uploads.md +1 -1
- data/doc/storage/memory.md +19 -0
- data/doc/storage/s3.md +102 -81
- data/doc/testing.md +2 -2
- data/doc/upgrading_to_3.md +94 -32
- data/lib/shrine.rb +3 -2
- data/lib/shrine/attacher.rb +14 -9
- data/lib/shrine/plugins/add_metadata.rb +13 -0
- data/lib/shrine/plugins/derivatives.rb +8 -7
- data/lib/shrine/plugins/determine_mime_type.rb +3 -3
- data/lib/shrine/plugins/model.rb +1 -1
- data/lib/shrine/plugins/refresh_metadata.rb +2 -2
- data/lib/shrine/plugins/remove_invalid.rb +10 -5
- data/lib/shrine/plugins/type_predicates.rb +113 -0
- data/lib/shrine/plugins/validation.rb +8 -6
- data/lib/shrine/storage/s3.rb +34 -28
- data/lib/shrine/version.rb +1 -1
- metadata +7 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1879257b21d6aafee3739bb22a37c46abfb7703dde20120445134b4f0ca56a4d
|
4
|
+
data.tar.gz: c0351dafde054c2bb126b5e16c632cf4ee34ab61c9a301d68564fe75ab1f3d5f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 95f3ebbf6f08f799d385486464129cfd7228f04d957709593350671d066888bde0dbdc988aca6f843e0b0eb6f13e6938f81a032a272e999903de8fee5d588ca6
|
7
|
+
data.tar.gz: 4c8f7a1f64e914db4776fab9df2e9753456a095c993a626f45a1c1e1bc189eeb77f3c04187d4bd132f31a2edd163eea2fee21b360cf35a8f6991b970671d615e
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,21 @@
|
|
1
|
+
## 3.2.0 (2019-12-17) [[release notes]](https://shrinerb.com/docs/release_notes/3.2.0)
|
2
|
+
|
3
|
+
* `validation` – Run validation on `Attacher#attach` & `Attacher#attach_cached` instead of `Attacher#change` (@janko)
|
4
|
+
|
5
|
+
* `remove_invalid` – Activate also when `Attacher#validate` is run manually (@janko)
|
6
|
+
|
7
|
+
* `remove_invalid` – Fix incompatibility with `derivatives` plugin (@janko)
|
8
|
+
|
9
|
+
* `type_predicates` – Add new plugin with convenient `UploadedFile` predicate methods based on MIME type (@janko)
|
10
|
+
|
11
|
+
* `core` – Allow assigning back current attached file data (@janko)
|
12
|
+
|
13
|
+
* `derivatives` – Fix `:derivative` value inconsistency when derivatives are being promoted (@janko)
|
14
|
+
|
15
|
+
* `add_metadata` – Add `#add_metadata` method for adding metadata to uploaded files (@janko)
|
16
|
+
|
17
|
+
* `derivatives` – Add `:io` and `:attacher` values to instrumentation event payload (@janko)
|
18
|
+
|
1
19
|
## 3.1.0 (2019-11-15) [[release notes]](https://shrinerb.com/docs/release_notes/3.1.0)
|
2
20
|
|
3
21
|
* `default_storage` – Coerce storage key to symbol in `Attacher#cache_key` & `Attacher#store_key` (@janko)
|
data/README.md
CHANGED
@@ -8,7 +8,7 @@ Shrine is a toolkit for handling file attachments in Ruby applications. Some hig
|
|
8
8
|
* **Memory friendly** – streaming uploads and [downloads][Retrieving Uploads] make it work great with large files
|
9
9
|
* **Cloud storage** – store files on [disk][FileSystem], [AWS S3][S3], [Google Cloud][GCS], [Cloudinary] and others
|
10
10
|
* **Persistence integrations** – works with [Sequel], [ActiveRecord], [ROM], [Hanami] and [Mongoid] and others
|
11
|
-
* **Flexible processing** – generate thumbnails [
|
11
|
+
* **Flexible processing** – generate thumbnails [eagerly] or [on-the-fly] using [ImageMagick] or [libvips]
|
12
12
|
* **Metadata validation** – [validate files][validation] based on [extracted metadata][metadata]
|
13
13
|
* **Direct uploads** – upload asynchronously [to your app][simple upload] or [to the cloud][presigned upload] using [Uppy]
|
14
14
|
* **Resumable uploads** – make large file uploads [resumable][resumable upload] on [S3][uppy-s3_multipart] or [tus][tus-ruby-server]
|
@@ -149,8 +149,8 @@ The gem is available as open source under the terms of the [MIT License].
|
|
149
149
|
[ROM]: https://github.com/shrinerb/shrine-rom
|
150
150
|
[Hanami]: https://github.com/katafrakt/hanami-shrine
|
151
151
|
[Mongoid]: https://github.com/shrinerb/shrine-mongoid
|
152
|
-
[
|
153
|
-
[on-the-fly]: https://shrinerb.com/docs/getting-started#
|
152
|
+
[eagerly]: https://shrinerb.com/docs/getting-started#eager-processing
|
153
|
+
[on-the-fly]: https://shrinerb.com/docs/getting-started#on-the-fly-processing
|
154
154
|
[ImageMagick]: https://github.com/janko/image_processing/blob/master/doc/minimagick.md#readme
|
155
155
|
[libvips]: https://github.com/janko/image_processing/blob/master/doc/vips.md#readme
|
156
156
|
[validation]: https://shrinerb.com/docs/validation
|
data/doc/advantages.md
CHANGED
@@ -157,14 +157,14 @@ end
|
|
157
157
|
|
158
158
|
## Processing
|
159
159
|
|
160
|
-
Most file attachment libraries
|
161
|
-
(Paperclip, CarrierWave) or on-the-fly (Dragonfly, Refile, Active Storage).
|
160
|
+
Most file attachment libraries allow you to process files either "eagerly"
|
161
|
+
(Paperclip, CarrierWave) or "on-the-fly" (Dragonfly, Refile, Active Storage).
|
162
162
|
However, each approach is suitable for different requirements. For instance,
|
163
163
|
while on-the-fly processing is suitable for fast processing (image thumbnails,
|
164
164
|
document previews), longer running processing (video transcoding, raw images)
|
165
165
|
should be moved into a background job.
|
166
166
|
|
167
|
-
That's why Shrine supports both [
|
167
|
+
That's why Shrine supports both [eager][derivatives] and
|
168
168
|
[on-the-fly][derivation_endpoint] processing. For example, if you're handling
|
169
169
|
image uploads, you can choose to either generate a set of pre-defined
|
170
170
|
thumbnails during attachment:
|
data/doc/carrierwave.md
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
---
|
2
|
-
title:
|
2
|
+
title: Upgrading from CarrierWave
|
3
3
|
---
|
4
4
|
|
5
5
|
This guide is aimed at helping CarrierWave users transition to Shrine, and it
|
@@ -476,16 +476,25 @@ photo.image.original_filename #=> "avatar.jpg"
|
|
476
476
|
|
477
477
|
#### `#store_dir`, `#cache_dir`
|
478
478
|
|
479
|
-
Shrine here provides a `#generate_location` method
|
480
|
-
storages:
|
479
|
+
Shrine here provides a single `#generate_location` method that's triggered for
|
480
|
+
all storages:
|
481
481
|
|
482
482
|
```rb
|
483
483
|
class ImageUploader < Shrine
|
484
|
-
def generate_location(io, record: nil, **)
|
485
|
-
|
484
|
+
def generate_location(io, record: nil, name: nil, **)
|
485
|
+
[ storage_key,
|
486
|
+
record && record.class.name.underscore,
|
487
|
+
record && record.id,
|
488
|
+
super,
|
489
|
+
io.original_filename ].compact.join("/")
|
486
490
|
end
|
487
491
|
end
|
488
492
|
```
|
493
|
+
```
|
494
|
+
cache/user/123/2feff8c724e7ce17/nature.jpg
|
495
|
+
store/user/456/7f99669fde1e01fc/kitten.jpg
|
496
|
+
...
|
497
|
+
```
|
489
498
|
|
490
499
|
You might also want to use the `pretty_location` plugin for automatically
|
491
500
|
generating an organized folder structure.
|
@@ -498,8 +507,8 @@ For default URLs you can use the `default_url` plugin:
|
|
498
507
|
class ImageUploader < Shrine
|
499
508
|
plugin :default_url
|
500
509
|
|
501
|
-
Attacher.default_url do |
|
502
|
-
"/
|
510
|
+
Attacher.default_url do |derivative: nil, **|
|
511
|
+
"/fallbacks/#{derivative || "original"}.jpg"
|
503
512
|
end
|
504
513
|
end
|
505
514
|
```
|
@@ -654,7 +663,7 @@ shows what are Shrine's equivalents.
|
|
654
663
|
|
655
664
|
#### `root`, `base_path`, `permissions`, `directory_permissions`
|
656
665
|
|
657
|
-
In Shrine these are configured on the FileSystem storage directly.
|
666
|
+
In Shrine these are configured on the `FileSystem` storage directly.
|
658
667
|
|
659
668
|
#### `storage`, `storage_engines`
|
660
669
|
|
data/doc/design.md
CHANGED
@@ -2,22 +2,25 @@
|
|
2
2
|
title: The Design of Shrine
|
3
3
|
---
|
4
4
|
|
5
|
-
*If you want an in-depth walkthrough through the Shrine codebase, see [Notes on
|
5
|
+
*If you want an in-depth walkthrough through the Shrine codebase, see [Notes on
|
6
|
+
study of shrine implementation] article by Jonathan Rochkind.*
|
6
7
|
|
7
|
-
There are five main types of
|
8
|
+
There are five main types of classes that you deal with in Shrine:
|
8
9
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
10
|
+
| Class | Description |
|
11
|
+
| :---- | :---------- |
|
12
|
+
| `Shrine::Storage::*` | Manages files on a particular storage service |
|
13
|
+
| `Shrine` | Wraps uploads and handles loading plugins |
|
14
|
+
| `Shrine::UploadedFile` | Represents a file uploaded to a storage |
|
15
|
+
| `Shrine::Attacher` | Handles file attachment logic |
|
16
|
+
| `Shrine::Attachment` | Provides convenience model attachment interface |
|
14
17
|
|
15
18
|
## Storage
|
16
19
|
|
17
20
|
On the lowest level we have a storage. A storage class encapsulates file
|
18
21
|
management logic on a particular service. It is what actually performs uploads,
|
19
22
|
generation of URLs, deletions and similar. By convention it is namespaced under
|
20
|
-
`Shrine::Storage
|
23
|
+
`Shrine::Storage::*`.
|
21
24
|
|
22
25
|
```rb
|
23
26
|
filesystem = Shrine::Storage::FileSystem.new("uploads")
|
@@ -26,7 +29,7 @@ filesystem.url("foo") #=> "uploads/foo"
|
|
26
29
|
filesystem.delete("foo")
|
27
30
|
```
|
28
31
|
|
29
|
-
A storage is a PORO which
|
32
|
+
A storage is a PORO which implements the following interface:
|
30
33
|
|
31
34
|
```rb
|
32
35
|
class Shrine
|
@@ -56,13 +59,14 @@ class Shrine
|
|
56
59
|
end
|
57
60
|
```
|
58
61
|
|
59
|
-
Storages are typically not used directly, but through `Shrine
|
62
|
+
Storages are typically not used directly, but through [`Shrine`](#shrine) and
|
63
|
+
[`Shrine::UploadedFile`](#shrine-uploadedfile) classes.
|
60
64
|
|
61
65
|
## `Shrine`
|
62
66
|
|
63
|
-
|
64
|
-
|
65
|
-
name:
|
67
|
+
The `Shrine` class (also called an "uploader") primarily provides a wrapper
|
68
|
+
method around `Storage#upload`. First, the storage needs to be registered under
|
69
|
+
a name:
|
66
70
|
|
67
71
|
```rb
|
68
72
|
Shrine.storages[:disk] = Shrine::Storage::FileSystem.new("uploads")
|
@@ -72,7 +76,7 @@ Now we can upload files to the registered storage:
|
|
72
76
|
|
73
77
|
```rb
|
74
78
|
uploaded_file = Shrine.upload(file, :disk)
|
75
|
-
uploaded_file #=> #<Shrine::UploadedFile
|
79
|
+
uploaded_file #=> #<Shrine::UploadedFile storage=:disk id="6a9fb596cc554efb" ...>
|
76
80
|
```
|
77
81
|
|
78
82
|
The argument to `Shrine#upload` must be an IO-like object. The method does the
|
@@ -84,63 +88,97 @@ following:
|
|
84
88
|
* closes the file
|
85
89
|
* creates a `Shrine::UploadedFile` from the data
|
86
90
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
plugin
|
91
|
+
### Plugins
|
92
|
+
|
93
|
+
The `Shrine` class is also used for loading plugins, which provide additional
|
94
|
+
functionality by extending core classes.
|
95
|
+
|
96
|
+
```rb
|
97
|
+
Shrine.plugin :derivatives
|
98
|
+
|
99
|
+
Shrine::UploadedFile.ancestors #=> [..., Shrine::Plugins::Derivatives::FileMethods, Shrine::UploadedFile::InstanceMethods, ...]
|
100
|
+
Shrine::Attacher.ancestors #=> [..., Shrine::Plugins::Derivatives::AttacherMethods, Shrine::Attacher::InstanceMethods, ...]
|
101
|
+
Shrine::Attachment.ancestors #=> [..., Shrine::Plugins::Derivatives::AttachmentMethods, Shrine::Attachment::InstanceMethods, ...]
|
102
|
+
```
|
103
|
+
|
104
|
+
The plugins store their configuration in `Shrine.opts`:
|
105
|
+
|
106
|
+
```rb
|
107
|
+
Shrine.plugin :derivation_endpoint, secret_key: "foo"
|
108
|
+
Shrine.plugin :default_storage, store: :other_store
|
109
|
+
Shrine.plugin :activerecord
|
110
|
+
|
111
|
+
Shrine.opts #=>
|
112
|
+
# { derivation_endpoint: { options: { secret_key: "foo" }, derivations: {} },
|
113
|
+
# default_storage: { store: :other_store },
|
114
|
+
# column: { serializer: Shrine::Plugins::Column::JsonSerializer },
|
115
|
+
# model: { cache: true },
|
116
|
+
# activerecord: { callbacks: true, validations: true } }
|
117
|
+
```
|
118
|
+
|
119
|
+
Each `Shrine` subclass has its own copy of the core classes, storages and
|
120
|
+
options, which makes it possible to customize attachment logic per uploader.
|
121
|
+
|
122
|
+
```rb
|
123
|
+
MyUploader = Class.new(Shrine)
|
124
|
+
MyUploader::UploadedFile.superclass #=> Shrine::UploadedFile
|
125
|
+
MyUploader::Attacher.superclass #=> Shrine::Attacher
|
126
|
+
MyUploader::Attachment.superclass #=> Shrine::Attachment
|
127
|
+
```
|
128
|
+
|
129
|
+
See [Creating a New Plugin] guide and the [Plugin system of Sequel and Roda]
|
130
|
+
article for more details on the design of Shrine's plugin system.
|
94
131
|
|
95
132
|
## `Shrine::UploadedFile`
|
96
133
|
|
97
|
-
`Shrine::UploadedFile` represents a file that was uploaded to a
|
98
|
-
|
99
|
-
|
134
|
+
A `Shrine::UploadedFile` object represents a file that was uploaded to a
|
135
|
+
storage, containing upload location, storage, and any metadata extracted during
|
136
|
+
the upload.
|
100
137
|
|
101
138
|
```rb
|
102
|
-
uploaded_file
|
103
|
-
|
139
|
+
uploaded_file #=> #<Shrine::UploadedFile id="949sdjg834.jpg" storage=:store metadata={...}>
|
140
|
+
|
141
|
+
uploaded_file.id #=> "949sdjg834.jpg"
|
142
|
+
uploaded_file.storage_key #=> :store
|
143
|
+
uploaded_file.storage #=> #<Shrine::Storage::S3>
|
144
|
+
uploaded_file.metadata #=> {...}
|
145
|
+
```
|
146
|
+
|
147
|
+
It has convenience methods for accessing metadata:
|
148
|
+
|
149
|
+
```rb
|
150
|
+
uploaded_file.metadata #=>
|
104
151
|
# {
|
105
|
-
# "
|
106
|
-
# "
|
107
|
-
# "
|
108
|
-
# "filename" => "resume.pdf",
|
109
|
-
# "mime_type" => "application/pdf",
|
110
|
-
# "size" => 983294,
|
111
|
-
# },
|
152
|
+
# "filename" => "matrix.mp4",
|
153
|
+
# "mime_type" => "video/mp4",
|
154
|
+
# "size" => 345993,
|
112
155
|
# }
|
156
|
+
|
157
|
+
uploaded_file.original_filename #=> "matrix.mp4"
|
158
|
+
uploaded_file.extension #=> "mp4"
|
159
|
+
uploaded_file.mime_type #=> "video/mp4"
|
160
|
+
uploaded_file.size #=> 345993
|
113
161
|
```
|
114
162
|
|
115
|
-
|
116
|
-
some metadata: original filename, MIME type and filesize. The
|
117
|
-
`Shrine::UploadedFile` object has handy methods which use this data:
|
163
|
+
It also has methods that delegate to the storage:
|
118
164
|
|
119
165
|
```rb
|
120
|
-
|
121
|
-
uploaded_file.
|
122
|
-
uploaded_file.
|
123
|
-
uploaded_file.
|
124
|
-
|
125
|
-
|
126
|
-
# storage methods
|
127
|
-
uploaded_file.url
|
128
|
-
uploaded_file.exists?
|
129
|
-
uploaded_file.open
|
130
|
-
uploaded_file.download
|
131
|
-
uploaded_file.delete
|
132
|
-
# ...
|
166
|
+
uploaded_file.url #=> "https://my-bucket.s3.amazonaws.com/949sdjg834.jpg"
|
167
|
+
uploaded_file.open { |io| ... } # opens the uploaded file stream
|
168
|
+
uploaded_file.download { |file| ... } # downloads the uploaded file to disk
|
169
|
+
uploaded_file.stream(destination) # streams uploaded content into a writable destination
|
170
|
+
uploaded_file.exists? #=> true
|
171
|
+
uploaded_file.delete # deletes the uploaded file from the storage
|
133
172
|
```
|
134
173
|
|
135
|
-
A `Shrine::UploadedFile` is itself an IO-like object (
|
136
|
-
|
174
|
+
A `Shrine::UploadedFile` is itself an IO-like object (built on top of
|
175
|
+
`Storage#open`), so it can be passed to `Shrine#upload` as well.
|
137
176
|
|
138
177
|
## `Shrine::Attacher`
|
139
178
|
|
140
179
|
We usually want to treat uploaded files as *attachments* to records, saving
|
141
|
-
their data into a database column. This is
|
142
|
-
|
143
|
-
`Shrine::UploadedFile` objects internally.
|
180
|
+
their data into a database column. This is done by `Shrine::Attacher`, which
|
181
|
+
internally uses `Shrine` and `Shrine::UploadedFile` classes.
|
144
182
|
|
145
183
|
The attaching process requires a temporary and a permanent storage to be
|
146
184
|
registered (by default that's `:cache` and `:store`):
|
@@ -152,40 +190,50 @@ Shrine.storages = {
|
|
152
190
|
}
|
153
191
|
```
|
154
192
|
|
155
|
-
A `Shrine::Attacher`
|
156
|
-
|
193
|
+
A `Shrine::Attacher` can be initialized standalone and handle the common
|
194
|
+
attachment flow, which includes dirty tracking (promoting cached file to
|
195
|
+
permanent storage, deleting previously attached file), validation, processing,
|
196
|
+
serialization etc.
|
197
|
+
|
198
|
+
```rb
|
199
|
+
attacher = Shrine::Attacher.new
|
200
|
+
|
201
|
+
# ... user uploads a file ...
|
202
|
+
|
203
|
+
attacher.assign(io) # uploads to temporary storage
|
204
|
+
attacher.file #=> #<Shrine::UploadedFile storage=:cache ...>
|
205
|
+
|
206
|
+
# ... handle file validations ...
|
207
|
+
|
208
|
+
attacher.finalize # uploads to permanent storage
|
209
|
+
attacher.file #=> #<Shrine::UploadedFile storage=:store ...>
|
210
|
+
```
|
211
|
+
|
212
|
+
It can also be initialized with a model instance to handle serialization into a
|
213
|
+
model attribute:
|
157
214
|
|
158
215
|
```rb
|
159
216
|
attacher = Shrine::Attacher.from_model(photo, :image)
|
160
217
|
|
161
218
|
attacher.assign(file)
|
162
|
-
|
163
|
-
attacher.record.image_data #=> "{\"storage\":\"cache\",\"id\":\"9260ea09d8effd.jpg\",\"metadata\":{...}}"
|
219
|
+
photo.image_data #=> "{\"storage\":\"cache\",\"id\":\"9260ea09d8effd.jpg\",\"metadata\":{...}}"
|
164
220
|
|
165
221
|
attacher.finalize
|
166
|
-
|
167
|
-
attacher.record.image_data #=> "{\"storage\":\"store\",\"id\":\"ksdf02lr9sf3la.jpg\",\"metadata\":{...}}"
|
222
|
+
photo.image_data #=> "{\"storage\":\"store\",\"id\":\"ksdf02lr9sf3la.jpg\",\"metadata\":{...}}"
|
168
223
|
```
|
169
224
|
|
170
|
-
|
171
|
-
|
172
|
-
permanent storage. Behind the scenes a cached `Shrine::UploadedFile` is given
|
173
|
-
to `Shrine#upload`, which works because `Shrine::UploadedFile` is an IO-like
|
174
|
-
object. After both caching and promoting the data hash of the uploaded file is
|
175
|
-
assigned to the record's column as JSON.
|
176
|
-
|
177
|
-
For more details see [Using Attacher].
|
225
|
+
For more details, see the [Using Attacher] guide and
|
226
|
+
[`entity`][entity]/[`model`][model] plugins.
|
178
227
|
|
179
228
|
## `Shrine::Attachment`
|
180
229
|
|
181
|
-
`Shrine::Attachment`
|
182
|
-
`Shrine::
|
183
|
-
|
184
|
-
means that an instance of `Shrine::Attachment` is a module:
|
230
|
+
A `Shrine::Attachment` module provides a convenience model interface around the
|
231
|
+
`Shrine::Attacher` object. The `Shrine::Attachment` class is a subclass of
|
232
|
+
`Module`, which means that an instance of `Shrine::Attachment` is a module:
|
185
233
|
|
186
234
|
```rb
|
187
235
|
Shrine::Attachment.new(:image).is_a?(Module) #=> true
|
188
|
-
Shrine::Attachment.new(:image).instance_methods #=> [:image=, :image, :image_url, :image_attacher]
|
236
|
+
Shrine::Attachment.new(:image).instance_methods #=> [:image=, :image, :image_url, :image_attacher, ...]
|
189
237
|
|
190
238
|
# equivalents
|
191
239
|
Shrine::Attachment.new(:image)
|
@@ -193,30 +241,31 @@ Shrine::Attachment[:image]
|
|
193
241
|
Shrine::Attachment(:image)
|
194
242
|
```
|
195
243
|
|
196
|
-
We can include this module
|
244
|
+
We can include this module into a model:
|
197
245
|
|
198
246
|
```rb
|
199
|
-
|
200
|
-
include Shrine::Attachment(:image)
|
201
|
-
end
|
247
|
+
Photo.include Shrine::Attachment(:image)
|
202
248
|
```
|
203
249
|
```rb
|
204
|
-
photo.image = file
|
205
|
-
photo.image
|
206
|
-
photo.image_url
|
250
|
+
photo.image = file # shorthand for `photo.image_attacher.assign(file)`
|
251
|
+
photo.image # shorthand for `photo.image_attacher.get`
|
252
|
+
photo.image_url # shorthand for `photo.image_attacher.url`
|
207
253
|
|
208
|
-
photo.image_attacher #=> #<Shrine::Attacher
|
254
|
+
photo.image_attacher #=> #<Shrine::Attacher @cache_key=:cache @store_key=:store ...>
|
209
255
|
```
|
210
256
|
|
211
|
-
When a persistence plugin is loaded
|
212
|
-
automatically:
|
257
|
+
When a persistence plugin is loaded ([`activerecord`][activerecord],
|
258
|
+
[`sequel`][sequel]), the `Shrine::Attachment` module also automatically:
|
213
259
|
|
214
260
|
* syncs Shrine's validation errors with the record
|
215
261
|
* triggers promoting after record is saved
|
216
|
-
* deletes the uploaded file if attachment was replaced
|
217
|
-
destroyed
|
262
|
+
* deletes the uploaded file if attachment was replaced or the record destroyed
|
218
263
|
|
219
264
|
[Using Attacher]: https://shrinerb.com/docs/attacher
|
220
265
|
[Notes on study of shrine implementation]: https://bibwild.wordpress.com/2018/09/12/notes-on-study-of-shrine-implementation/
|
221
266
|
[Creating a New Plugin]: https://shrinerb.com/docs/creating-plugins
|
222
267
|
[Plugin system of Sequel and Roda]: https://twin.github.io/the-plugin-system-of-sequel-and-roda/
|
268
|
+
[entity]: https://shrinerb.com/docs/plugins/entity
|
269
|
+
[model]: https://shrinerb.com/docs/plugins/model
|
270
|
+
[activerecord]: https://shrinerb.com/docs/plugins/activerecord
|
271
|
+
[sequel]: https://shrinerb.com/docs/plugins/sequel
|
data/doc/external/articles.md
CHANGED
@@ -17,6 +17,7 @@ title: Articles
|
|
17
17
|
* [Better File Uploads with Shrine: Processing](https://twin.github.io/better-file-uploads-with-shrine-processing/)
|
18
18
|
* [Better File Uploads with Shrine: Metadata](https://twin.github.io/better-file-uploads-with-shrine-metadata/)
|
19
19
|
* [Better File Uploads with Shrine: Direct Uploads](https://twin.github.io/better-file-uploads-with-shrine-direct-uploads)
|
20
|
+
* [Upcoming Features in Shrine 3.0](https://twin.github.io/upcoming-features-in-shrine-3-0/)
|
20
21
|
* [Shrine 3.0 Released](https://twin.github.io/shrine-3-0-released/)
|
21
22
|
|
22
23
|
## Other Articles
|