carrierwave_direct_mongoid 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/LICENSE +21 -0
- data/README.md +404 -0
- data/Rakefile +12 -0
- data/carrierwave_direct_mongoid.gemspec +31 -0
- data/lib/carrierwave_direct/mongoid/version.rb +8 -0
- data/lib/carrierwave_direct/mongoid.rb +57 -0
- data/lib/carrierwave_direct_mongoid.rb +1 -0
- data/spec/mongoid_spec.rb +23 -0
- data/spec/spec_helper.rb +10 -0
- data/spec/support/carrier_wave_config.rb +11 -0
- data/spec/support/direct_uploader.rb +8 -0
- data/spec/support/form_builder_helpers.rb +37 -0
- data/spec/support/global_helpers.rb +8 -0
- data/spec/support/model_helpers.rb +82 -0
- data/spec/support/mounted_class.rb +10 -0
- data/spec/support/uploader_helpers.rb +12 -0
- data/spec/support/view_helpers.rb +47 -0
- metadata +163 -0
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Copyright (c) David Wilkie
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
21
|
+
|
data/README.md
ADDED
@@ -0,0 +1,404 @@
|
|
1
|
+
# CarrierWaveDirect
|
2
|
+
|
3
|
+
[![Build Status](https://secure.travis-ci.org/dwilkie/carrierwave_direct.png)](http://travis-ci.org/dwilkie/carrierwave_direct)
|
4
|
+
|
5
|
+
[CarrierWave](https://github.com/jnicklas/carrierwave) is a great way to upload files from Ruby applications, but since processing and saving is done in-process, it doesn't scale well. A better way is to upload your files directly then handle the processing and saving in a background process.
|
6
|
+
|
7
|
+
[CarrierWaveDirect](https://github.com/dwilkie/carrierwave_direct) works on top of [CarrierWave](https://github.com/jnicklas/carrierwave) and provides a simple way to achieve this.
|
8
|
+
|
9
|
+
## Compatibility
|
10
|
+
|
11
|
+
Right now, CarrierWaveDirect works with [Amazon S3](http://aws.amazon.com/s3/). Adding support for [Google Storage for Developers](http://code.google.com/apis/storage/) should be fairly straight forward since the direct upload form is essentially the same. Please see the contributing section if you would like support for Google Storage for Developers or any other service that provides direct upload capabilities.
|
12
|
+
|
13
|
+
Please be aware that this gem (and S3 in general) only support single file uploads. If you want to upload multiple files simultaneously you'll have to use a javascript or flash uploader.
|
14
|
+
|
15
|
+
## Information
|
16
|
+
|
17
|
+
More information, and how-tos [available on the wiki](https://github.com/dwilkie/carrierwave_direct/wiki)
|
18
|
+
|
19
|
+
## Installation
|
20
|
+
|
21
|
+
Install the latest release:
|
22
|
+
|
23
|
+
gem install carrierwave_direct
|
24
|
+
|
25
|
+
In Rails, add it to your Gemfile:
|
26
|
+
|
27
|
+
gem 'carrierwave_direct'
|
28
|
+
|
29
|
+
Note that CarrierWaveDirect is not compatible with Rails 2.
|
30
|
+
|
31
|
+
## Getting Started
|
32
|
+
|
33
|
+
Please read the [CarrierWave readme](https://github.com/jnicklas/carrierwave) first
|
34
|
+
|
35
|
+
CarrierWaveDirect works with [fog](https://github.com/geemus/fog) so make sure you have [CarrierWave](https://github.com/jnicklas/carrierwave) set up and initialized with your fog credentials, for example:
|
36
|
+
|
37
|
+
CarrierWave.configure do |config|
|
38
|
+
config.fog_credentials = {
|
39
|
+
:provider => 'AWS', # required
|
40
|
+
:aws_access_key_id => 'xxx', # required
|
41
|
+
:aws_secret_access_key => 'yyy', # required
|
42
|
+
:region => 'eu-west-1' # optional, defaults to 'us-east-1'
|
43
|
+
}
|
44
|
+
config.fog_directory = 'name_of_directory' # required
|
45
|
+
config.fog_host = 'https://assets.example.com' # optional, defaults to nil
|
46
|
+
config.fog_public = false # optional, defaults to true
|
47
|
+
config.fog_attributes = {'Cache-Control'=>'max-age=315576000'} # optional, defaults to {}
|
48
|
+
end
|
49
|
+
|
50
|
+
If you haven't already done so generate an uploader
|
51
|
+
|
52
|
+
rails generate uploader Avatar
|
53
|
+
|
54
|
+
this should give you a file in:
|
55
|
+
|
56
|
+
app/uploaders/avatar_uploader.rb
|
57
|
+
|
58
|
+
Check out this file for some hints on how you can customize your uploader. It should look something like this:
|
59
|
+
|
60
|
+
class AvatarUploader < CarrierWave::Uploader::Base
|
61
|
+
storage :file
|
62
|
+
end
|
63
|
+
|
64
|
+
Remove the line `storage :file` and replace it with `include CarrierWaveDirect::Uploader` so it should look something like:
|
65
|
+
|
66
|
+
class AvatarUploader < CarrierWave::Uploader::Base
|
67
|
+
include CarrierWaveDirect::Uploader
|
68
|
+
end
|
69
|
+
|
70
|
+
This adds the extra functionality for direct uploading.
|
71
|
+
|
72
|
+
Finally, remove the `store_dir` method in order to default CarrierWaveDirect to its own storage directory.
|
73
|
+
|
74
|
+
If you're *not* using Rails you can generate a direct upload form to S3 similar to [this example](http://doc.s3.amazonaws.com/proposals/post.html#A_Sample_Form)) by making use of the CarrierWaveDirect helper methods.
|
75
|
+
|
76
|
+
### Sinatra
|
77
|
+
|
78
|
+
Here is an example using Sinatra and Haml
|
79
|
+
|
80
|
+
# uploader_test.rb
|
81
|
+
|
82
|
+
CarrierWave.configure do |config|
|
83
|
+
config.fog_credentials = {
|
84
|
+
:provider => 'AWS',
|
85
|
+
:aws_access_key_id => ENV['AWS_ACCESS_KEY_ID'],
|
86
|
+
:aws_secret_access_key => ENV['AWS_SECRET_ACCESS_KEY']
|
87
|
+
}
|
88
|
+
config.fog_directory = ENV['AWS_FOG_DIRECTORY'] # bucket name
|
89
|
+
end
|
90
|
+
|
91
|
+
class ImageUploader < CarrierWave::Uploader::Base
|
92
|
+
include CarrierWaveDirect::Uploader
|
93
|
+
end
|
94
|
+
|
95
|
+
class UploaderTest < Sinatra::Base
|
96
|
+
get "/" do
|
97
|
+
@uploader = ImageUploader.new
|
98
|
+
@uploader.success_action_redirect = request.url
|
99
|
+
haml :index
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# index.haml
|
104
|
+
|
105
|
+
%form{:action => @uploader.direct_fog_url, :method => "post", :enctype => "multipart/form-data"}
|
106
|
+
%input{:name => "utf8", :type => "hidden"}
|
107
|
+
%input{:type => "hidden", :name => "key", :value => @uploader.key}
|
108
|
+
%input{:type => "hidden", :name => "AWSAccessKeyId", :value => @uploader.aws_access_key_id}
|
109
|
+
%input{:type => "hidden", :name => "acl", :value => @uploader.acl}
|
110
|
+
%input{:type => "hidden", :name => "success_action_redirect", :value => @uploader.success_action_redirect}
|
111
|
+
%input{:type => "hidden", :name => "policy", :value => @uploader.policy}
|
112
|
+
%input{:type => "hidden", :name => "signature", :value => @uploader.signature}
|
113
|
+
%input{:name => "file", :type => "file"}
|
114
|
+
%input{:type => "submit", :value => "Upload to S3"}
|
115
|
+
|
116
|
+
### Rails
|
117
|
+
|
118
|
+
If you *are* using Rails and you've mounted your uploader like this:
|
119
|
+
|
120
|
+
class User < ActiveRecord::Base
|
121
|
+
mount_uploader :avatar, AvatarUploader
|
122
|
+
end
|
123
|
+
|
124
|
+
things just got a whole lot easier. You can generate a direct upload form like this:
|
125
|
+
|
126
|
+
class AvatarController < ApplicationController
|
127
|
+
def new
|
128
|
+
@uploader = User.new.avatar
|
129
|
+
@uploader.success_action_redirect = new_user_url
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
<%= direct_upload_form_for @uploader do |f| %>
|
134
|
+
<%= f.file_field :avatar %>
|
135
|
+
<%= f.submit %>
|
136
|
+
<% end %>
|
137
|
+
|
138
|
+
You can also pass html options like this:
|
139
|
+
|
140
|
+
<%= direct_upload_form_for @uploader, :html => { :target => "_blank_iframe" } do |f| %>
|
141
|
+
<%= f.file_field :avatar %>
|
142
|
+
<%= f.submit %>
|
143
|
+
<% end %>
|
144
|
+
|
145
|
+
Note if `User` is not an ActiveRecord object e.g.
|
146
|
+
|
147
|
+
class User
|
148
|
+
mount_uploader :avatar, AvatarUploader
|
149
|
+
end
|
150
|
+
|
151
|
+
you can still use the form helper by including the ActiveModel modules your uploader:
|
152
|
+
|
153
|
+
class AvatarUploader < CarrierWave::Uploader::Base
|
154
|
+
include CarrierWaveDirect::Uploader
|
155
|
+
|
156
|
+
include ActiveModel::Conversion
|
157
|
+
extend ActiveModel::Naming
|
158
|
+
end
|
159
|
+
|
160
|
+
Note if you're using Rails 3.0.x you'll also need to disable forgery protection
|
161
|
+
|
162
|
+
# config/application.rb
|
163
|
+
config.action_controller.allow_forgery_protection = false
|
164
|
+
|
165
|
+
Once you've uploaded your file directly to the cloud you'll probably need a way to reference it with an ORM and process it.
|
166
|
+
|
167
|
+
## Processing and referencing files in a background process
|
168
|
+
|
169
|
+
Processing and saving file uploads are typically long running tasks and should be done in a background process. CarrierWaveDirect gives you a few methods to help you do this with your favorite background processor such as [DelayedJob](https://github.com/collectiveidea/delayed_job) or [Resque](https://github.com/defunkt/resque).
|
170
|
+
|
171
|
+
If your upload was successful then you will be redirected to the `success_action_redirect` url you specified in your uploader. S3 replies with a redirect like this: `http://example.com?bucket=your_fog_directory&key=uploads%2Fguid%2Ffile.ext&etag=%22d41d8cd98f00b204e9800998ecf8427%22`
|
172
|
+
|
173
|
+
The `key` is the most important piece of information as we can use it for validating the file extension, downloading the file from S3, processing it and re-uploading it.
|
174
|
+
|
175
|
+
If you're using ActiveRecord, CarrierWaveDirect will by default validate the file extension based off your `extension_white_list` in your uploader. See the [CarrierWave readme](https://github.com/jnicklas/carrierwave) for more info. You can then use the helper `filename_valid?` to check if the filename is valid. e.g.
|
176
|
+
|
177
|
+
class UsersController < ApplicationController
|
178
|
+
def new
|
179
|
+
@user = User.new(params)
|
180
|
+
unless @user.filename_valid?
|
181
|
+
flash[:error] = @user.errors.full_messages.to_sentence
|
182
|
+
redirect_to new_avatar_path
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
CarrierWaveDirect automatically gives you an accessible `key` attribute in your mounted model when using ActiveRecord. You can use this to put a hidden field for the `key` into your model's form.
|
188
|
+
|
189
|
+
<%= form_for @user do |f| %>
|
190
|
+
<%= f.hidden_field :key %>
|
191
|
+
<%= f.label :email %>
|
192
|
+
<%= f.text_field :email %>
|
193
|
+
<%= f.submit %>
|
194
|
+
<% end %>
|
195
|
+
|
196
|
+
then in your controller you can do something like this:
|
197
|
+
|
198
|
+
def create
|
199
|
+
@user = User.new(params[:user])
|
200
|
+
if @user.save_and_process_avatar
|
201
|
+
flash[:notice] = "User being created"
|
202
|
+
redirect_to :action => :index
|
203
|
+
else
|
204
|
+
render :new
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
### Background processing
|
209
|
+
|
210
|
+
Now that the basic building blocks are in place you can process and save your avatar in the background. This example uses [Resque](https://github.com/defunkt/resque) but the same logic could be applied to [DelayedJob](https://github.com/collectiveidea/delayed_job) or any other background processor.
|
211
|
+
|
212
|
+
class User < ActiveRecord::Base
|
213
|
+
def save_and_process_avatar(options = {})
|
214
|
+
if options[:now]
|
215
|
+
self.remote_avatar_url = avatar.direct_fog_url(:with_path => true)
|
216
|
+
save
|
217
|
+
else
|
218
|
+
Resque.enqueue(AvatarProcessor, attributes)
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
class AvatarProcessor
|
224
|
+
@queue = :avatar_processor_queue
|
225
|
+
|
226
|
+
def self.perform(attributes)
|
227
|
+
user = User.new(attributes)
|
228
|
+
user.save_and_process_avatar(:now => true)
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
The method `self.remote_avatar_url=` from [CarrierWave](https://github.com/jnicklas/carrierwave) downloads the avatar from S3 and processes it. `save` then re-uploads the processed avatar to to S3
|
233
|
+
|
234
|
+
## Uploading from a remote location
|
235
|
+
|
236
|
+
Your users may find it convenient to upload a file from a location on the Internet via a URL. CarrierWaveDirect gives you another accessor to achieve this.
|
237
|
+
|
238
|
+
<%= form_for @user do |f| %>
|
239
|
+
<%= f.hidden_field :key %>
|
240
|
+
<% unless @user.has_avatar_upload? %>
|
241
|
+
<%= f.label :remote_avatar_net_url %>
|
242
|
+
<%= f.text_field :remote_avatar_net_url %>
|
243
|
+
<%= f.submit %>
|
244
|
+
<% end %>
|
245
|
+
|
246
|
+
|
247
|
+
class User < ActiveRecord::Base
|
248
|
+
def save_and_process_avatar(options = {})
|
249
|
+
if options[:now]
|
250
|
+
self.remote_avatar_url = has_remote_avatar_net_url? ? remote_avatar_net_url : avatar.direct_fog_url(:with_path => true)
|
251
|
+
save
|
252
|
+
else
|
253
|
+
Resque.enqueue(AvatarProcessor, attributes)
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
The methods `has_avatar_upload?`, `remote_avatar_net_url` and `has_remote_avatar_net_url?` are automatically added to your mounted model
|
259
|
+
|
260
|
+
## Validations
|
261
|
+
|
262
|
+
Along with validating the extension of the filename, CarrierWaveDirect also gives you some other validations:
|
263
|
+
|
264
|
+
validates :avatar :is_uploaded => true
|
265
|
+
|
266
|
+
Validates that your mounted model has an avatar uploaded from file or specified by remote url. It does not check that an your mounted model actually has a valid avatar after the download has taken place. Turned *off* by default
|
267
|
+
|
268
|
+
validates :avatar, :is_attached => true
|
269
|
+
|
270
|
+
Validates that your mounted model has an avatar attached. This checks whether there is an actual avatar attached to the mounted model after downloading. Turned *off* by default
|
271
|
+
|
272
|
+
validates :avatar, :filename_uniqueness => true
|
273
|
+
|
274
|
+
Validates that the filename in the database is unique. Turned *on* by default
|
275
|
+
|
276
|
+
validates :avatar :filename_format => true
|
277
|
+
|
278
|
+
Validates that the uploaded filename is valid. As well as validating the extension against the `extension_white_list` it also validates that the `upload_dir` is correct. Turned *on* by default
|
279
|
+
|
280
|
+
validates :avatar :remote_net_url_format => true
|
281
|
+
|
282
|
+
Validates that the remote net url is valid. As well as validating the extension against the `extension_white_list` it also validates that url is valid and has only the schemes specified in the `url_scheme_whitelist`. Turned *on* by default
|
283
|
+
|
284
|
+
## Configuration
|
285
|
+
|
286
|
+
As well as the built in validations CarrierWaveDirect provides, some validations, such as max file size and upload expiration can be performed on the S3 side.
|
287
|
+
|
288
|
+
CarrierWave.configure do |config|
|
289
|
+
config.validate_is_attached = true # defaults to false
|
290
|
+
config.validate_is_uploaded = true # defaults to false
|
291
|
+
config.validate_unique_filename = false # defaults to true
|
292
|
+
config.validate_filename_format = false # defaults to true
|
293
|
+
config.validate_remote_net_url_format = false # defaults to true
|
294
|
+
|
295
|
+
config.max_file_size = 10.megabytes # defaults to 5.megabytes
|
296
|
+
config.upload_expiration = 1.hour # defaults to 10.hours
|
297
|
+
end
|
298
|
+
|
299
|
+
## Testing with CarrierWaveDirect
|
300
|
+
|
301
|
+
CarrierWaveDirect provides a couple of helpers to help with integration and unit testing. You don't want to contact the Internet during your tests as this is slow, expensive and unreliable. You should first put fog into mock mode by doing something like this.
|
302
|
+
|
303
|
+
Fog.mock!
|
304
|
+
|
305
|
+
def fog_directory
|
306
|
+
ENV['AWS_FOG_DIRECTORY']
|
307
|
+
end
|
308
|
+
|
309
|
+
connection = ::Fog::Storage.new(
|
310
|
+
:aws_access_key_id => ENV['AWS_ACCESS_KEY_ID'],
|
311
|
+
:aws_secret_access_key => ENV['AWS_SECRET_ACCESS_KEY'],
|
312
|
+
:provider => 'AWS'
|
313
|
+
)
|
314
|
+
|
315
|
+
connection.directories.create(:key => fog_directory)
|
316
|
+
|
317
|
+
### Using Capybara
|
318
|
+
|
319
|
+
If your using Capybara with Cucumber or RSpec, CarrierWaveDirect gives you a few useful helpers. To get the Capybara helpers, include the module into your test file or helper
|
320
|
+
|
321
|
+
describe AvatarUploadSpec
|
322
|
+
include CarrierWaveDirect::Test::CapybaraHelpers
|
323
|
+
end
|
324
|
+
|
325
|
+
To attach a file to the direct upload form you can use
|
326
|
+
|
327
|
+
attach_file_for_direct_upload('path/to/file.ext')
|
328
|
+
|
329
|
+
To simulate a successful upload and redirect to S3 you can use
|
330
|
+
|
331
|
+
upload_directly(AvatarUploader, "Upload to S3")
|
332
|
+
|
333
|
+
This will click the Upload to S3 button on the form and redirect you to the `success_action_redirect` url (in the form) with a sample response from S3
|
334
|
+
|
335
|
+
To simulate an unsuccessful upload you can pass `:success => false` and you'll remain on the upload page e.g.
|
336
|
+
|
337
|
+
upload_directly(AvatarUploader, "Upload to S3", :success => false)
|
338
|
+
|
339
|
+
You can also use `find_key` and `find_upload_path` to get the key and upload path from the form
|
340
|
+
|
341
|
+
### Unit tests
|
342
|
+
|
343
|
+
If your mounted model validates a file is uploaded you might want to make use of the `sample_key` method
|
344
|
+
|
345
|
+
include CarrierWaveDirect::Test::Helpers
|
346
|
+
|
347
|
+
Factory.define :user |f|
|
348
|
+
f.email "some1@example.com"
|
349
|
+
f.key { sample_key(AvatarUploader.new) }
|
350
|
+
end
|
351
|
+
|
352
|
+
This will return a valid key based off your `upload_dir` and your `extension_white_list`
|
353
|
+
|
354
|
+
### Faking a background download
|
355
|
+
|
356
|
+
If you wanted to fake a download in the background you could do something like this
|
357
|
+
|
358
|
+
uploader = AvatarUploader.new
|
359
|
+
|
360
|
+
upload_path = find_upload_path
|
361
|
+
redirect_key = sample_key(:base => find_key, :filename => File.basename(upload_path))
|
362
|
+
|
363
|
+
uploader.key = redirect_key
|
364
|
+
download_url = uploader.direct_fog_url(:with_path => true)
|
365
|
+
|
366
|
+
# Register the download url and return the uploaded file in the body
|
367
|
+
FakeWeb.register_uri(:get, download_url, :body => File.open(upload_path))
|
368
|
+
|
369
|
+
## i18n
|
370
|
+
|
371
|
+
The Active Record validations use the Rails i18n framework. Add these keys to your translations file:
|
372
|
+
|
373
|
+
en:
|
374
|
+
errors:
|
375
|
+
messages:
|
376
|
+
carrierwave_direct_filename_taken: filename was already taken
|
377
|
+
carrierwave_direct_upload_missing: upload is missing
|
378
|
+
carrierwave_direct_attachment_missing: attachment is missing
|
379
|
+
carrierwave_direct_filename_invalid: is invalid. Allowed file types are %{extension_white_list}
|
380
|
+
carrierwave_direct_remote_net_url_invalid: is invalid. Allowed file types are %{extension_white_list}. Allowed url schemes are %{url_scheme_white_list}
|
381
|
+
|
382
|
+
## Caveats
|
383
|
+
|
384
|
+
Don't name your string column `file`. It will result in a stack level too deep exception. See [this issue](https://github.com/dwilkie/carrierwave_direct/issues/10) for more info
|
385
|
+
|
386
|
+
## Contributing to CarrierWaveDirect
|
387
|
+
|
388
|
+
Pull requests are very welcome. Before submitting a pull request, please make sure that your changes are well tested.
|
389
|
+
|
390
|
+
gem install bundler
|
391
|
+
bundle install
|
392
|
+
|
393
|
+
You should now be able to run the tests
|
394
|
+
|
395
|
+
bundle exec rake
|
396
|
+
|
397
|
+
## Contributors
|
398
|
+
|
399
|
+
* [cblunt (Chris Blunt)](https://github.com/cblunt) - Support for passing html options
|
400
|
+
* [robyurkowski (Rob Yurkowski)](https://github.com/robyurkowski) - Fix deprecation warnings for Rails 3.2
|
401
|
+
* [tylr (Tyler Love)](https://github.com/tylr) - Bug fix
|
402
|
+
* [vlado (Vlado Cingel)](https://github.com/vlado) - Properly sanitize filename
|
403
|
+
* [travisp (Travis Pew)](https://github.com/travisp) - Compatibility for CarrierWave 0.6.0
|
404
|
+
* [jgorset (Johannes Gorset)](https://github.com/jgorset) - Added note about removing 'store_dir' in README
|
data/Rakefile
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "carrierwave_direct/mongoid/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "carrierwave_direct_mongoid"
|
7
|
+
s.version = CarrierwaveDirect::Mongoid::VERSION
|
8
|
+
s.authors = ["David Wilkie"]
|
9
|
+
s.email = ["dwilkie@gmail.com"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = %q{Upload direct to S3 using CarrierWave}
|
12
|
+
s.description = %q{Process your uploads in the background by uploading directly to S3}
|
13
|
+
|
14
|
+
# s.rubyforge_project = "carrierwave_direct_mongoid"
|
15
|
+
|
16
|
+
s.add_dependency "carrierwave-mongoid"
|
17
|
+
s.add_dependency "carrierwave_direct"
|
18
|
+
|
19
|
+
s.add_development_dependency "rspec"
|
20
|
+
s.add_development_dependency "timecop"
|
21
|
+
s.add_development_dependency "rails"
|
22
|
+
s.add_development_dependency "sqlite3"
|
23
|
+
s.add_development_dependency "capybara"
|
24
|
+
s.add_development_dependency "bson_ext"
|
25
|
+
|
26
|
+
s.files = `git ls-files`.split("\n")
|
27
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
28
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
29
|
+
s.require_paths = ["lib"]
|
30
|
+
end
|
31
|
+
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'mongoid'
|
4
|
+
require 'carrierwave/mongoid'
|
5
|
+
require 'carrierwave_direct'
|
6
|
+
require 'carrierwave_direct/mount'
|
7
|
+
require 'carrierwave_direct/validations/active_model'
|
8
|
+
|
9
|
+
module CarrierWaveDirect
|
10
|
+
module Mongoid
|
11
|
+
include CarrierWaveDirect::Mount
|
12
|
+
|
13
|
+
def mount_uploader(column, uploader=nil, options={}, &block)
|
14
|
+
super
|
15
|
+
|
16
|
+
uploader.instance_eval <<-RUBY, __FILE__, __LINE__+1
|
17
|
+
include ActiveModel::Conversion
|
18
|
+
extend ActiveModel::Naming
|
19
|
+
RUBY
|
20
|
+
|
21
|
+
include CarrierWaveDirect::Validations::ActiveModel
|
22
|
+
|
23
|
+
validates_is_attached column if uploader_option(column.to_sym, :validate_is_attached)
|
24
|
+
validates_is_uploaded column if uploader_option(column.to_sym, :validate_is_uploaded)
|
25
|
+
validates_filename_uniqueness_of column if uploader_option(column.to_sym, :validate_unique_filename)
|
26
|
+
validates_filename_format_of column if uploader_option(column.to_sym, :validate_filename_format)
|
27
|
+
validates_remote_net_url_format_of column if uploader_option(column.to_sym, :validate_remote_net_url_format)
|
28
|
+
|
29
|
+
self.instance_eval <<-RUBY, __FILE__, __LINE__+1
|
30
|
+
attr_accessor :skip_is_attached_validations
|
31
|
+
attr_accessible :key, :remote_#{column}_net_url
|
32
|
+
RUBY
|
33
|
+
|
34
|
+
mod = Module.new
|
35
|
+
include mod
|
36
|
+
mod.class_eval <<-RUBY, __FILE__, __LINE__+1
|
37
|
+
def filename_valid?
|
38
|
+
if has_#{column}_upload?
|
39
|
+
self.skip_is_attached_validations = true
|
40
|
+
valid?
|
41
|
+
self.skip_is_attached_validations = false
|
42
|
+
column_errors = errors[:#{column}]
|
43
|
+
errors.clear
|
44
|
+
column_errors.each do |column_error|
|
45
|
+
errors.add(:#{column}, column_error)
|
46
|
+
end
|
47
|
+
errors.empty?
|
48
|
+
else
|
49
|
+
true
|
50
|
+
end
|
51
|
+
end
|
52
|
+
RUBY
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
Mongoid::Document::ClassMethods.send :include, CarrierWaveDirect::Mongoid
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'carrierwave_direct/mongoid'
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'carrierwave_direct/mongoid'
|
3
|
+
|
4
|
+
describe CarrierWaveDirect::Mongoid do
|
5
|
+
class MyDocument
|
6
|
+
include Mongoid::Document
|
7
|
+
mount_uploader :video, DirectUploader
|
8
|
+
end
|
9
|
+
|
10
|
+
subject { MyDocument.new }
|
11
|
+
|
12
|
+
describe "#key" do
|
13
|
+
it "should be accessible" do
|
14
|
+
MyDocument.new(:key => "some key").key.should == "some key"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "Uploader#model_name" do
|
19
|
+
it "should work" do
|
20
|
+
MyDocument.new.video.model_name.should == "DirectUploader"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
CarrierWave.configure do |config|
|
4
|
+
config.fog_credentials = {
|
5
|
+
:provider => 'AWS',
|
6
|
+
:aws_access_key_id => 'AWS_ACCESS_KEY_ID',
|
7
|
+
:aws_secret_access_key => 'AWS_SECRET_ACCESS_KEY'
|
8
|
+
}
|
9
|
+
config.fog_directory = 'AWS_FOG_DIRECTORY' # bucket name
|
10
|
+
end
|
11
|
+
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'action_view'
|
4
|
+
require 'action_view/template'
|
5
|
+
|
6
|
+
require File.join(File.dirname(__FILE__), 'view_helpers')
|
7
|
+
|
8
|
+
require 'carrierwave_direct/form_builder'
|
9
|
+
require 'carrierwave_direct/action_view_extensions/form_helper'
|
10
|
+
|
11
|
+
module FormBuilderHelpers
|
12
|
+
include ActionView::Helpers::FormHelper
|
13
|
+
include CarrierWaveDirect::ActionViewExtensions::FormHelper
|
14
|
+
include ActionView::Context
|
15
|
+
include ActionController::RecordIdentifier
|
16
|
+
|
17
|
+
include ::ViewHelpers
|
18
|
+
|
19
|
+
def direct_uploader
|
20
|
+
defined?(super) ? super : @direct_uploader ||= MountedClass.new.video
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.included(base)
|
24
|
+
DirectUploader.send(:include, ActiveModel::Conversion)
|
25
|
+
DirectUploader.extend ActiveModel::Naming
|
26
|
+
end
|
27
|
+
|
28
|
+
def protect_against_forgery?
|
29
|
+
false
|
30
|
+
end
|
31
|
+
|
32
|
+
def form(options = {}, &block)
|
33
|
+
blk = block_given? ? block : Proc.new {|f|}
|
34
|
+
direct_upload_form_for(direct_uploader, options, &blk)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module ModelHelpers
|
4
|
+
def self.included(base)
|
5
|
+
base.extend ClassMethods
|
6
|
+
end
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
def it_should_be_accessible(name, sample_data, options = {})
|
10
|
+
describe "when initialized with .new(:#{name} => '#{sample_data}')" do
|
11
|
+
|
12
|
+
let(:accessor_value) do
|
13
|
+
subject.class.send(:new, { name => sample_data }).send(name)
|
14
|
+
end
|
15
|
+
|
16
|
+
if options[:accessible]
|
17
|
+
if options[:accessible] == true
|
18
|
+
it "should == '#{sample_data}'" do
|
19
|
+
accessor_value.should == sample_data
|
20
|
+
end
|
21
|
+
else
|
22
|
+
it "##{options[:accessible].keys.first} should be #{options[:accessible].values.first}" do
|
23
|
+
subject.send(options[:accessible].keys.first).should == options[:accessible].values.first
|
24
|
+
end
|
25
|
+
end
|
26
|
+
else
|
27
|
+
it "should be nil" do
|
28
|
+
accessor_value.should be_nil
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def it_should_delegate(name, options = {})
|
35
|
+
sample_data = "sample_#{name.to_s}"
|
36
|
+
delegation_object, delegation_method = options[:to].split("#")
|
37
|
+
|
38
|
+
describe "##{name} = '#{sample_data}'" do
|
39
|
+
it "should set the #{delegation_object}'s #{delegation_method}" do
|
40
|
+
subject.send("#{name}=", sample_data)
|
41
|
+
subject.send(delegation_object).send(delegation_method).should == sample_data
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "##{name}" do
|
46
|
+
it "should return the #{delegation_method} from the #{delegation_object}" do
|
47
|
+
subject.send(delegation_object).send("#{delegation_method}=", sample_data)
|
48
|
+
subject.send(name).should == sample_data
|
49
|
+
end
|
50
|
+
|
51
|
+
it_should_be_accessible(name, sample_data, options)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def it_should_have_accessor(name, options = {})
|
56
|
+
if name.is_a?(Hash)
|
57
|
+
key = name.keys.first
|
58
|
+
sample_data = name[key]
|
59
|
+
name = key
|
60
|
+
else
|
61
|
+
sample_data = "sample_#{name.to_s}"
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should respond to ##{name}=" do
|
65
|
+
subject.should respond_to("#{name}=")
|
66
|
+
end
|
67
|
+
|
68
|
+
describe "##{name}" do
|
69
|
+
context "where the #{name} is set to '#{sample_data}'" do
|
70
|
+
before { subject.send("#{name}=", sample_data) }
|
71
|
+
|
72
|
+
it "should == '#{sample_data}'" do
|
73
|
+
subject.send(name).should == sample_data
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
it_should_be_accessible(name, sample_data, options) if options[:accessible].present?
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'capybara/rspec'
|
4
|
+
|
5
|
+
module ViewHelpers
|
6
|
+
include Capybara::RSpecMatchers
|
7
|
+
|
8
|
+
def parent_selector
|
9
|
+
defined?(super) ? super : @parent_selector ||= []
|
10
|
+
end
|
11
|
+
|
12
|
+
def have_parent_selector(options = {})
|
13
|
+
have_selector(:xpath, parent_selector_xpath, options)
|
14
|
+
end
|
15
|
+
|
16
|
+
def parent_selector_xpath
|
17
|
+
xpath = parent_selector.join("/")
|
18
|
+
xpath = ".//#{xpath}" unless xpath[0..2] == ".//"
|
19
|
+
xpath
|
20
|
+
end
|
21
|
+
|
22
|
+
def submit_to(options = {})
|
23
|
+
xpath_attributes = to_xpath_attributes(options)
|
24
|
+
parent_selector << "form[#{xpath_attributes}]"
|
25
|
+
have_parent_selector
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_xpath_attributes(options = {})
|
29
|
+
attributes = []
|
30
|
+
|
31
|
+
options.each do |key, value|
|
32
|
+
attributes << ((value == false) ? "not(@#{key})" : "@#{key}='#{value}'")
|
33
|
+
end
|
34
|
+
|
35
|
+
attributes.join(" and ")
|
36
|
+
end
|
37
|
+
|
38
|
+
def have_input(resource_name, input, options = {})
|
39
|
+
options[:type] ||= input
|
40
|
+
options[:id] ||= "#{resource_name}_#{input}"
|
41
|
+
options[:name] ||= "#{resource_name}[#{input}]"
|
42
|
+
options[:required] ||= "required" unless options[:required] == false
|
43
|
+
parent_selector << "input[#{to_xpath_attributes(options)}]"
|
44
|
+
have_parent_selector
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
metadata
ADDED
@@ -0,0 +1,163 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: carrierwave_direct_mongoid
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.6
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- David Wilkie
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-06-15 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: carrierwave-mongoid
|
16
|
+
requirement: &70245758983840 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70245758983840
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: carrierwave_direct
|
27
|
+
requirement: &70245758983000 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70245758983000
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: rspec
|
38
|
+
requirement: &70245758982120 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *70245758982120
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: timecop
|
49
|
+
requirement: &70245758981360 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *70245758981360
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: rails
|
60
|
+
requirement: &70245759033540 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
type: :development
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *70245759033540
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: sqlite3
|
71
|
+
requirement: &70245759032700 !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ! '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: *70245759032700
|
80
|
+
- !ruby/object:Gem::Dependency
|
81
|
+
name: capybara
|
82
|
+
requirement: &70245759032200 !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
84
|
+
requirements:
|
85
|
+
- - ! '>='
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
type: :development
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: *70245759032200
|
91
|
+
- !ruby/object:Gem::Dependency
|
92
|
+
name: bson_ext
|
93
|
+
requirement: &70245759031620 !ruby/object:Gem::Requirement
|
94
|
+
none: false
|
95
|
+
requirements:
|
96
|
+
- - ! '>='
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
99
|
+
type: :development
|
100
|
+
prerelease: false
|
101
|
+
version_requirements: *70245759031620
|
102
|
+
description: Process your uploads in the background by uploading directly to S3
|
103
|
+
email:
|
104
|
+
- dwilkie@gmail.com
|
105
|
+
executables: []
|
106
|
+
extensions: []
|
107
|
+
extra_rdoc_files: []
|
108
|
+
files:
|
109
|
+
- .gitignore
|
110
|
+
- .travis.yml
|
111
|
+
- Gemfile
|
112
|
+
- LICENSE
|
113
|
+
- README.md
|
114
|
+
- Rakefile
|
115
|
+
- carrierwave_direct_mongoid.gemspec
|
116
|
+
- lib/carrierwave_direct/mongoid.rb
|
117
|
+
- lib/carrierwave_direct/mongoid/version.rb
|
118
|
+
- lib/carrierwave_direct_mongoid.rb
|
119
|
+
- spec/mongoid_spec.rb
|
120
|
+
- spec/spec_helper.rb
|
121
|
+
- spec/support/carrier_wave_config.rb
|
122
|
+
- spec/support/direct_uploader.rb
|
123
|
+
- spec/support/form_builder_helpers.rb
|
124
|
+
- spec/support/global_helpers.rb
|
125
|
+
- spec/support/model_helpers.rb
|
126
|
+
- spec/support/mounted_class.rb
|
127
|
+
- spec/support/uploader_helpers.rb
|
128
|
+
- spec/support/view_helpers.rb
|
129
|
+
homepage: ''
|
130
|
+
licenses: []
|
131
|
+
post_install_message:
|
132
|
+
rdoc_options: []
|
133
|
+
require_paths:
|
134
|
+
- lib
|
135
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
136
|
+
none: false
|
137
|
+
requirements:
|
138
|
+
- - ! '>='
|
139
|
+
- !ruby/object:Gem::Version
|
140
|
+
version: '0'
|
141
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
142
|
+
none: false
|
143
|
+
requirements:
|
144
|
+
- - ! '>='
|
145
|
+
- !ruby/object:Gem::Version
|
146
|
+
version: '0'
|
147
|
+
requirements: []
|
148
|
+
rubyforge_project:
|
149
|
+
rubygems_version: 1.8.15
|
150
|
+
signing_key:
|
151
|
+
specification_version: 3
|
152
|
+
summary: Upload direct to S3 using CarrierWave
|
153
|
+
test_files:
|
154
|
+
- spec/mongoid_spec.rb
|
155
|
+
- spec/spec_helper.rb
|
156
|
+
- spec/support/carrier_wave_config.rb
|
157
|
+
- spec/support/direct_uploader.rb
|
158
|
+
- spec/support/form_builder_helpers.rb
|
159
|
+
- spec/support/global_helpers.rb
|
160
|
+
- spec/support/model_helpers.rb
|
161
|
+
- spec/support/mounted_class.rb
|
162
|
+
- spec/support/uploader_helpers.rb
|
163
|
+
- spec/support/view_helpers.rb
|