defile 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +27 -0
- data/.rspec +1 -0
- data/.travis.yml +8 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +466 -0
- data/Rakefile +11 -0
- data/app/assets/javascripts/defile.js +50 -0
- data/app/helpers/attachment_helper.rb +50 -0
- data/config.ru +8 -0
- data/config/locales/en.yml +5 -0
- data/config/routes.rb +3 -0
- data/defile.gemspec +34 -0
- data/lib/defile.rb +72 -0
- data/lib/defile/app.rb +97 -0
- data/lib/defile/attachment.rb +89 -0
- data/lib/defile/attachment/active_record.rb +24 -0
- data/lib/defile/backend/file_system.rb +70 -0
- data/lib/defile/backend/s3.rb +129 -0
- data/lib/defile/file.rb +65 -0
- data/lib/defile/image_processing.rb +73 -0
- data/lib/defile/rails.rb +36 -0
- data/lib/defile/random_hasher.rb +5 -0
- data/lib/defile/version.rb +3 -0
- data/spec/defile/app_spec.rb +151 -0
- data/spec/defile/attachment_spec.rb +141 -0
- data/spec/defile/backend/file_system_spec.rb +30 -0
- data/spec/defile/backend/s3_spec.rb +11 -0
- data/spec/defile/backend_examples.rb +215 -0
- data/spec/defile/features/direct_upload_spec.rb +29 -0
- data/spec/defile/features/normal_upload_spec.rb +36 -0
- data/spec/defile/features/presigned_upload_spec.rb +29 -0
- data/spec/defile/fixtures/hello.txt +1 -0
- data/spec/defile/fixtures/large.txt +44 -0
- data/spec/defile/spec_helper.rb +58 -0
- data/spec/defile/test_app.rb +46 -0
- data/spec/defile/test_app/app/assets/javascripts/application.js +40 -0
- data/spec/defile/test_app/app/controllers/application_controller.rb +2 -0
- data/spec/defile/test_app/app/controllers/direct_posts_controller.rb +15 -0
- data/spec/defile/test_app/app/controllers/home_controller.rb +4 -0
- data/spec/defile/test_app/app/controllers/normal_posts_controller.rb +19 -0
- data/spec/defile/test_app/app/controllers/presigned_posts_controller.rb +30 -0
- data/spec/defile/test_app/app/models/post.rb +5 -0
- data/spec/defile/test_app/app/views/direct_posts/new.html.erb +16 -0
- data/spec/defile/test_app/app/views/home/index.html.erb +1 -0
- data/spec/defile/test_app/app/views/layouts/application.html.erb +14 -0
- data/spec/defile/test_app/app/views/normal_posts/new.html.erb +20 -0
- data/spec/defile/test_app/app/views/normal_posts/show.html.erb +9 -0
- data/spec/defile/test_app/app/views/presigned_posts/new.html.erb +16 -0
- data/spec/defile/test_app/config/database.yml +7 -0
- data/spec/defile/test_app/config/routes.rb +17 -0
- data/spec/defile/test_app/public/favicon.ico +0 -0
- data/spec/defile_spec.rb +35 -0
- metadata +294 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: d2bbb1e9c99cb337359ac4aa0e5c27974e7fb6f0
|
4
|
+
data.tar.gz: 03df667144adc0818f2377b97b74e28d4e27713b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e9b48b6fa1da665fe19ff206f7575659b424ae0caab182f0d66d6bf7008ea5efc9fb7252eaac793b4306fb5f9659f2aa56ecf70e3e9db56fce617eba29b609c9
|
7
|
+
data.tar.gz: 2df044121ef0ed6821897500ff194fc832ae91911b05a0b8c13f499a942a9f09652275fc49a0eab58e79b98d522a8aa45205fd3d660a4401f1e86751ee80e5d2
|
data/.gitignore
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
*.bundle
|
19
|
+
*.so
|
20
|
+
*.o
|
21
|
+
*.a
|
22
|
+
mkmf.log
|
23
|
+
|
24
|
+
s3.yml
|
25
|
+
spec/defile/test_app/log
|
26
|
+
spec/defile/test_app/tmp
|
27
|
+
spec/defile/test_app/db/*.sqlite
|
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
-r defile/spec_helper
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Jonas Nicklas
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,466 @@
|
|
1
|
+
# Defile
|
2
|
+
|
3
|
+
Defile is a modern file upload library for Ruby applications. It is simple, yet
|
4
|
+
powerful. Defile is an attempt by CarrierWave's original author to fix the
|
5
|
+
design mistakes and overengineering in CarrierWave.
|
6
|
+
|
7
|
+
Features:
|
8
|
+
|
9
|
+
- Configurable backends, file system, S3, etc...
|
10
|
+
- Convenient integration with ORMs
|
11
|
+
- On the fly manipulation of images and other files
|
12
|
+
- Streaming IO for fast and memory friendly uploads
|
13
|
+
- Works across form redisplays, i.e. when validations fail, even on S3
|
14
|
+
- Effortless direct uploads, even to S3
|
15
|
+
|
16
|
+
## Quick start, Rails
|
17
|
+
|
18
|
+
Add the gem:
|
19
|
+
|
20
|
+
``` ruby
|
21
|
+
gem "mini_magick"
|
22
|
+
gem "defile", require: ["defile/rails", "defile/image_processing"]
|
23
|
+
```
|
24
|
+
|
25
|
+
Use the `attachment` method to use Defile in a model:
|
26
|
+
|
27
|
+
``` ruby
|
28
|
+
class User < ActiveRecord::Base
|
29
|
+
attachment :profile_image
|
30
|
+
end
|
31
|
+
```
|
32
|
+
|
33
|
+
Generate a migration:
|
34
|
+
|
35
|
+
``` sh
|
36
|
+
rails generate migration add_profile_image_to_users profile_image_id:string
|
37
|
+
rake db:migrate
|
38
|
+
```
|
39
|
+
|
40
|
+
Add an attachment field to your form:
|
41
|
+
|
42
|
+
``` erb
|
43
|
+
<%= form_for @user do |form| %>
|
44
|
+
<%= form.attachment_field :profile_image %>
|
45
|
+
<% end %>
|
46
|
+
```
|
47
|
+
|
48
|
+
Set up strong parameters:
|
49
|
+
|
50
|
+
``` ruby
|
51
|
+
def user_params
|
52
|
+
params.require(:user).permit(:profile_image, :profile_image_cache_id)
|
53
|
+
end
|
54
|
+
```
|
55
|
+
|
56
|
+
And start uploading! Finally show the file in your view:
|
57
|
+
|
58
|
+
``` erb
|
59
|
+
<%= image_tag attachment_url(@user, :profile_image, :fill, 300, 300) %>
|
60
|
+
```
|
61
|
+
|
62
|
+
## How it works
|
63
|
+
|
64
|
+
Defile consists of several parts:
|
65
|
+
|
66
|
+
1. Backends: cache and persist files
|
67
|
+
2. Model attachments: map files to model columns
|
68
|
+
3. A Rack application: streams files and accepts uploads
|
69
|
+
4. Rails helpers: conveniently generate markup in your views
|
70
|
+
4. A JavaScript library: facilitates direct uploads
|
71
|
+
|
72
|
+
Let's look at each of these in more detail!
|
73
|
+
|
74
|
+
## 1. Backend
|
75
|
+
|
76
|
+
Files are uploaded to a backend. The backend assigns an ID to this file, which
|
77
|
+
will be unique for this file within the backend.
|
78
|
+
|
79
|
+
Let's look at a simple example of using the backend:
|
80
|
+
|
81
|
+
``` ruby
|
82
|
+
backend = Defile::Backend::FileSystem.new("tmp")
|
83
|
+
|
84
|
+
file = backend.upload(StringIO.new("hello"))
|
85
|
+
file.id # => "b205bc..."
|
86
|
+
file.read # => "hello"
|
87
|
+
|
88
|
+
backend.get(file.id).read # => "hello"
|
89
|
+
```
|
90
|
+
|
91
|
+
As you may notice, backends are "flat". Files do not have directories, nor do
|
92
|
+
they have names or permissions, they are only identified by their ID.
|
93
|
+
|
94
|
+
Defile has a global registry of backends, accessed through `Defile.backends`.
|
95
|
+
|
96
|
+
There are two "special" backends, which are only really special in that they
|
97
|
+
are the default backends for attachments. They are `cache` and `store`.
|
98
|
+
|
99
|
+
The cache is intended to be transient. Files are added here before they are
|
100
|
+
meant to be permanently stored. Usually files are then moved to the store for
|
101
|
+
permanent storage, but this isn't always the case.
|
102
|
+
|
103
|
+
Suppose for example that a user uploads a file in a form and receives a
|
104
|
+
validation error. In that case the file has been temporarily stored in the
|
105
|
+
cache. The user might decide to fix the error and resubmit, at which point the
|
106
|
+
file will be promoted to the store. On the other hand, the user might simply
|
107
|
+
give up and leave, now the file is left in the cache for later cleanup.
|
108
|
+
|
109
|
+
Defile has convenient accessors for setting the `cache` and `store`, so for
|
110
|
+
example you can switch to the S3 backend like this:
|
111
|
+
|
112
|
+
``` ruby
|
113
|
+
# config/initializers/defile.rb
|
114
|
+
require "defile/backend/s3"
|
115
|
+
|
116
|
+
aws = {
|
117
|
+
access_key_id: "xyz",
|
118
|
+
secret_access_key: "abc",
|
119
|
+
bucket: "my-bucket",
|
120
|
+
}
|
121
|
+
Defile.cache = Defile::Backend::S3.new(prefix: "cache", **aws)
|
122
|
+
Defile.store = Defile::Backend::S3.new(prefix: "store", **aws)
|
123
|
+
```
|
124
|
+
|
125
|
+
Try this in the quick start example above and your files are now uploaded to
|
126
|
+
S3.
|
127
|
+
|
128
|
+
Backends also provide the option of restricting the size of files they accept.
|
129
|
+
For example:
|
130
|
+
|
131
|
+
``` ruby
|
132
|
+
Defile.cache = Defile::Backend::S3.new(max_size: 10.megabytes, ...)
|
133
|
+
```
|
134
|
+
|
135
|
+
### Uploadable
|
136
|
+
|
137
|
+
The `upload` method on backends can be called with a variety of objects. It
|
138
|
+
requires that the object passed to it behaves similarly to Ruby IO objects, in
|
139
|
+
particular it must implement the methods `size`, `read(length = nil, buffer =
|
140
|
+
nil)`, `eof?` and `close`. All of `File`, `Tempfile`,
|
141
|
+
`ActionDispath::UploadedFile` and `StringIO` implement this interface, however
|
142
|
+
`String` does not. If you want to upload a file from a `String` you must wrap
|
143
|
+
it in a `StringIO` first.
|
144
|
+
|
145
|
+
## 2. Attachments
|
146
|
+
|
147
|
+
You've already seen the `attachment` method:
|
148
|
+
|
149
|
+
``` ruby
|
150
|
+
class User < ActiveRecord::Base
|
151
|
+
attachment :profile_image
|
152
|
+
end
|
153
|
+
```
|
154
|
+
|
155
|
+
Calling `attachment` generates a getter and setter with the given name. When
|
156
|
+
you assign a file to the setter, it is uploaded to the cache:
|
157
|
+
|
158
|
+
``` ruby
|
159
|
+
User.new
|
160
|
+
|
161
|
+
# with a ActionDispatch::UploadedFile
|
162
|
+
user.profile_image = params[:file]
|
163
|
+
|
164
|
+
# with a regular File object
|
165
|
+
File.open("/some/path", "rb") do |file|
|
166
|
+
user.profile_image = file
|
167
|
+
end
|
168
|
+
|
169
|
+
# or a StringIO
|
170
|
+
user.profile_image = StringIO.new("hello world")
|
171
|
+
|
172
|
+
user.profile_image.id # => "fec421..."
|
173
|
+
user.profile_image.read # => "hello world"
|
174
|
+
```
|
175
|
+
|
176
|
+
When you call `save` on the record, the uploaded file is transferred from the
|
177
|
+
cache to the store. Where possible, Defile does this move efficiently. For example
|
178
|
+
if both `cache` and `store` are on the same S3 account, instead of downloading
|
179
|
+
the file and uploading it again, Defile will simply issue a copy command to S3.
|
180
|
+
|
181
|
+
### Other ORMs
|
182
|
+
|
183
|
+
Defile is built to integrate with ORMs other than ActiveRecord, but this being
|
184
|
+
a very young gem, such integrations do not yet exist. Take a look at the [ActiveRecord
|
185
|
+
integration](lib/defile/attachment/active_record.rb), building your own should
|
186
|
+
not be too difficult.
|
187
|
+
|
188
|
+
### Pure Ruby classes
|
189
|
+
|
190
|
+
You can also use attachments in pure Ruby classes like this:
|
191
|
+
|
192
|
+
``` ruby
|
193
|
+
class User
|
194
|
+
extend Defile::Attachment
|
195
|
+
|
196
|
+
attr_accessor :profile_image_id
|
197
|
+
|
198
|
+
attachment :profile_image
|
199
|
+
end
|
200
|
+
```
|
201
|
+
|
202
|
+
## 3. Rack Application
|
203
|
+
|
204
|
+
Defile includes a Rack application (an endpoint, not a middleware). This application
|
205
|
+
streams files from backends and can even accept file uploads and upload them to
|
206
|
+
backends.
|
207
|
+
|
208
|
+
**Important:** Unlike other file upload solutions, Defile always streams your files thorugh your
|
209
|
+
application. It cannot generate URLs to your files. This means that you should
|
210
|
+
**always** put a CDN or other HTTP cache in front of your application. Serving
|
211
|
+
files through your app takes a lot of resources and you want it to happen rarely.
|
212
|
+
|
213
|
+
This restriction, while onerous, is at the same time what makes Defile so easy
|
214
|
+
and pleasant to use.
|
215
|
+
|
216
|
+
### Mounting
|
217
|
+
|
218
|
+
If you are using Rails and have required [defile/rails.rb](lib/defile/rails.rb),
|
219
|
+
then the Rack application is mounted for you at `/attachments`. You should be able
|
220
|
+
to see this when you run `rake routes`.
|
221
|
+
|
222
|
+
You could also run the application on its own, it doesn't need to be mounted to
|
223
|
+
work.
|
224
|
+
|
225
|
+
### Retrieving files
|
226
|
+
|
227
|
+
Files can be retrieved from the application by calling:
|
228
|
+
|
229
|
+
```
|
230
|
+
GET /attachments/:backend_name/:id/:filename
|
231
|
+
```
|
232
|
+
|
233
|
+
The `:filename` serves no other purpose than generating a nice name when the user
|
234
|
+
downloads the file, it does not in any way affect the downloaded file. For caching
|
235
|
+
purposes you should always use the same filename for the same file. The Rails helpers
|
236
|
+
default this to the name of the column.
|
237
|
+
|
238
|
+
### Processing
|
239
|
+
|
240
|
+
Defile provides on the fly processing of files. You can trigger it by calling
|
241
|
+
a URL like this:
|
242
|
+
|
243
|
+
```
|
244
|
+
GET /attachments/:backend_name/:processor_name/*args/:id/:filename
|
245
|
+
```
|
246
|
+
|
247
|
+
Suppose we have uploaded a file:
|
248
|
+
|
249
|
+
``` ruby
|
250
|
+
Defile.cache.upload(StringIO.new("hello")).id # => "a4e8ce"
|
251
|
+
```
|
252
|
+
|
253
|
+
And we've defined a processor like this:
|
254
|
+
|
255
|
+
``` ruby
|
256
|
+
Defile.processor :reverse do |file|
|
257
|
+
StringIO.new(file.read.reverse)
|
258
|
+
end
|
259
|
+
```
|
260
|
+
|
261
|
+
Then you could do the following.
|
262
|
+
|
263
|
+
``` sh
|
264
|
+
curl http://127.0.0.1:3000/attachments/cache/reverse/a4e8ce/some_file.txt
|
265
|
+
elloh
|
266
|
+
```
|
267
|
+
|
268
|
+
Defile calls `call` on the processor and passes in the retrieved file, as well
|
269
|
+
as all additional arguments sent through the URL. See the
|
270
|
+
[built in image processors](lib/defile/image_processing.rb) for a more advanced
|
271
|
+
example.
|
272
|
+
|
273
|
+
## 4. Rails helpers
|
274
|
+
|
275
|
+
Defile provides the `attachment_field` form helper which generates a file field
|
276
|
+
as well as a hidden field, suffixed with `cache_id`. This field keeps track of
|
277
|
+
the file in case it is not yet permanently stored, for example if validations
|
278
|
+
fail. It is also used for direct and presigned uploads. For this reason it is
|
279
|
+
highly recommended to use `attachment_field` instead of `file_field`.
|
280
|
+
|
281
|
+
``` erb
|
282
|
+
<%= form_for @user do |form| %>
|
283
|
+
<%= form.attachment_field :profile_image %>
|
284
|
+
<% end %>
|
285
|
+
```
|
286
|
+
|
287
|
+
Will generate something like:
|
288
|
+
|
289
|
+
``` html
|
290
|
+
<form action="/users" enctype="multipart/form-data" method="post">
|
291
|
+
<input name="user[profile_image_cache_id]" type="hidden">
|
292
|
+
<input name="user[profile_image]" type="file">
|
293
|
+
</form>
|
294
|
+
```
|
295
|
+
|
296
|
+
The `attachment_url` helper can then be used for generating URLs for the uploaded
|
297
|
+
files:
|
298
|
+
|
299
|
+
``` erb
|
300
|
+
<%= image_tag attachment_url(@user, :profile_image) %>
|
301
|
+
```
|
302
|
+
|
303
|
+
Any additional arguments to it are included in the URL as processor arguments:
|
304
|
+
|
305
|
+
``` erb
|
306
|
+
<%= image_tag attachment_url(@user, :profile_image, :fill, 300, 300) %>
|
307
|
+
```
|
308
|
+
|
309
|
+
## 5. JavaScript library
|
310
|
+
|
311
|
+
Defile's JavaScript library is small but powerful.
|
312
|
+
|
313
|
+
Uploading files is slow, so anything we can do to speed up the process is going
|
314
|
+
to lead to happier users. One way to cheat is to start uploading files directly
|
315
|
+
after the user has chosen a file, instead of waiting until they hit the submit
|
316
|
+
button. This provides a significantly better user experience. Implementing this
|
317
|
+
is usually tricky, but thankfully Defile makes it very easy.
|
318
|
+
|
319
|
+
First, load the JavaScript file. If you're using the asset pipeline, you can
|
320
|
+
simply include it like this:
|
321
|
+
|
322
|
+
``` javascript
|
323
|
+
//= require defile
|
324
|
+
```
|
325
|
+
|
326
|
+
Otherwise you can grab a copy [here](https://raw.githubusercontent.com/jnicklas/defile/master/app/assets/javascripts/defile.js).
|
327
|
+
|
328
|
+
Now mark the field for direct upload:
|
329
|
+
|
330
|
+
``` erb
|
331
|
+
<%= form.attachment_field :profile_image, direct: true %>
|
332
|
+
```
|
333
|
+
|
334
|
+
There is no step 3 ;)
|
335
|
+
|
336
|
+
The file is now uploaded to the `cache` immediately after the user chooses a file.
|
337
|
+
If you try this in the browser, you'll notice that an AJAX request is fired as
|
338
|
+
soon as you choose a file. Then when you submit to the server, the file is no
|
339
|
+
longer submitted, only its id.
|
340
|
+
|
341
|
+
If you want to improve the experience of this, the JavaScript library fires
|
342
|
+
a couple of custom DOM events. These events bubble, so you can also listen for
|
343
|
+
them on the form for example:
|
344
|
+
|
345
|
+
``` javascript
|
346
|
+
form.addEventListener("upload:start", function() {
|
347
|
+
// ...
|
348
|
+
});
|
349
|
+
|
350
|
+
form.addEventListener("upload:success", function() {
|
351
|
+
// ...
|
352
|
+
});
|
353
|
+
|
354
|
+
input.addEventListener("upload:progress", function() {
|
355
|
+
// ...
|
356
|
+
});
|
357
|
+
```
|
358
|
+
|
359
|
+
You can also listen for them with jQuery, even with event delegation:
|
360
|
+
|
361
|
+
``` javascript
|
362
|
+
$(document).on("upload:start", "form", function(e) {
|
363
|
+
// ...
|
364
|
+
});
|
365
|
+
```
|
366
|
+
|
367
|
+
This way you could for example disable the submit button until all files have
|
368
|
+
uploaded:
|
369
|
+
|
370
|
+
``` javascript
|
371
|
+
$(document).on("upload:start", "form", function(e) {
|
372
|
+
$(this).find("input[type=submit]").attr("disabled", true)
|
373
|
+
});
|
374
|
+
|
375
|
+
$(document).on("upload:complete", "form", function(e) {
|
376
|
+
if(!$(this).find("input.uploading").length) {
|
377
|
+
$(this).find("input[type=submit]").removeAttr("disabled")
|
378
|
+
}
|
379
|
+
});
|
380
|
+
```
|
381
|
+
|
382
|
+
### Presigned uploads
|
383
|
+
|
384
|
+
Amazon S3 supports uploads directly from the browser to S3 buckets. With this
|
385
|
+
feature you can bypass your application entirely; uploads never hit your application
|
386
|
+
at all. Unfortunately the default configuration of S3 buckets does not allow
|
387
|
+
cross site AJAX requests from posting to buckets. Fixing this is easy though.
|
388
|
+
|
389
|
+
- Open the AWS S3 console and locate your bucket
|
390
|
+
- Right click on it and choose "Properties"
|
391
|
+
- Open the "Permission" section
|
392
|
+
- Click "Add CORS Configuration"
|
393
|
+
|
394
|
+
The default configuration only allows "GET", you'll want to allow "POST" as well.
|
395
|
+
It could look something like this:
|
396
|
+
|
397
|
+
``` xml
|
398
|
+
<CORSConfiguration>
|
399
|
+
<CORSRule>
|
400
|
+
<AllowedOrigin>*</AllowedOrigin>
|
401
|
+
<AllowedMethod>GET</AllowedMethod>
|
402
|
+
<AllowedMethod>POST</AllowedMethod>
|
403
|
+
<MaxAgeSeconds>3000</MaxAgeSeconds>
|
404
|
+
<AllowedHeader>Authorization</AllowedHeader>
|
405
|
+
</CORSRule>
|
406
|
+
</CORSConfiguration>
|
407
|
+
```
|
408
|
+
|
409
|
+
If you're paranoid you can restrict the allowed origin to only your domain, but
|
410
|
+
since your bucket is only writable with authentication anyway, this shouldn't
|
411
|
+
be necessary.
|
412
|
+
|
413
|
+
Note that you do not need to, and in fact you shouldn't, make your bucket world
|
414
|
+
writable.
|
415
|
+
|
416
|
+
Once you've put in the new configuration, click "Save".
|
417
|
+
|
418
|
+
Now you can enable presigned uploads:
|
419
|
+
|
420
|
+
``` erb
|
421
|
+
<%= form.attachment_field :profile_image, presigned: true %>
|
422
|
+
```
|
423
|
+
|
424
|
+
You can also enable both direct and presigned uploads, and it'll fall back to
|
425
|
+
direct uploads if presigned uploads aren't available. This is useful if you're
|
426
|
+
using the FileSystem backend in development or test mode and the S3 backend in
|
427
|
+
production mode.
|
428
|
+
|
429
|
+
``` erb
|
430
|
+
<%= form.attachment_field :profile_image, direct: true, presigned: true %>
|
431
|
+
```
|
432
|
+
|
433
|
+
### Browser compatibility
|
434
|
+
|
435
|
+
Defile's JavaScript library requires HTML5 features which are unavailable on
|
436
|
+
IE9 and earlier versions. All other major browsers are supported. Note though
|
437
|
+
that it has not yet been extensively tested.
|
438
|
+
|
439
|
+
## Cache expiry
|
440
|
+
|
441
|
+
Files will accumulate in your cache, and you'll probably want to remove them
|
442
|
+
after some time.
|
443
|
+
|
444
|
+
The FileSystem backend does not currently provide any method of doing this. PRs
|
445
|
+
welcome ;)
|
446
|
+
|
447
|
+
On S3 this can be conveniently handled through lifecycle rules. Exactly how
|
448
|
+
depends a bit on your setup. If you are using the suggested setup of having
|
449
|
+
one bucket with `cache` and `store` being directories in that bucket (or prefixes
|
450
|
+
in S3 parlance), then follow the following steps, otherwise adapt them to your
|
451
|
+
needs:
|
452
|
+
|
453
|
+
- Open the AWS S3 console and locate your bucket
|
454
|
+
- Right click on it and choose "Properties"
|
455
|
+
- Open the "Lifecycle" section
|
456
|
+
- Click "Add rule"
|
457
|
+
- Choose "Apply the rule to: A prefix"
|
458
|
+
- Enter "cache/" as the prefix (trailing slash!)
|
459
|
+
- Click "Configure rule"
|
460
|
+
- For "Action on Objects" you'll probably want to choose "Permanently Delete Only"
|
461
|
+
- Choose whatever number of days you're comfortable with, I chose "1"
|
462
|
+
- Click "Review" and finally "Create and activate Rule"
|
463
|
+
|
464
|
+
## License
|
465
|
+
|
466
|
+
[MIT](LICENSE.txt)
|