jnicklas-carrierwave 0.2.2 → 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +35 -20
- data/Rakefile +1 -1
- data/lib/carrierwave/compatibility/paperclip.rb +91 -0
- data/lib/carrierwave/core_ext/inheritable_attributes.rb +102 -0
- data/lib/carrierwave/core_ext/module_setup.rb +49 -0
- data/lib/carrierwave/mount.rb +119 -103
- data/lib/carrierwave/orm/activerecord.rb +6 -1
- data/lib/carrierwave/orm/sequel.rb +15 -2
- data/lib/carrierwave/processing/rmagick.rb +8 -7
- data/lib/carrierwave/storage/abstract.rb +16 -1
- data/lib/carrierwave/storage/file.rb +20 -1
- data/lib/carrierwave/uploader/cache.rb +114 -0
- data/lib/carrierwave/uploader/callbacks.rb +40 -0
- data/lib/carrierwave/uploader/default_path.rb +21 -0
- data/lib/carrierwave/uploader/extension_whitelist.rb +35 -0
- data/lib/carrierwave/uploader/mountable.rb +37 -0
- data/lib/carrierwave/uploader/paths.rb +25 -0
- data/lib/carrierwave/uploader/processing.rb +79 -0
- data/lib/carrierwave/uploader/proxy.rb +60 -0
- data/lib/carrierwave/uploader/remove.rb +21 -0
- data/lib/carrierwave/uploader/store.rb +154 -0
- data/lib/carrierwave/uploader/url.rb +22 -0
- data/lib/carrierwave/uploader/versions.rb +145 -0
- data/lib/carrierwave/uploader.rb +31 -593
- data/lib/carrierwave.rb +55 -7
- data/lib/generators/uploader_generator.rb +1 -1
- data/rails_generators/uploader/templates/uploader.rb +12 -8
- data/spec/compatibility/paperclip_spec.rb +41 -0
- data/spec/mount_spec.rb +88 -25
- data/spec/orm/activerecord_spec.rb +7 -9
- data/spec/orm/datamapper_spec.rb +7 -9
- data/spec/orm/sequel_spec.rb +47 -32
- data/spec/spec_helper.rb +13 -0
- data/spec/uploader/cache_spec.rb +194 -0
- data/spec/uploader/default_path_spec.rb +66 -0
- data/spec/uploader/extension_whitelist_spec.rb +42 -0
- data/spec/uploader/mountable_spec.rb +31 -0
- data/spec/uploader/paths_spec.rb +20 -0
- data/spec/uploader/processing_spec.rb +60 -0
- data/spec/uploader/proxy_spec.rb +52 -0
- data/spec/uploader/remove_spec.rb +65 -0
- data/spec/uploader/store_spec.rb +260 -0
- data/spec/uploader/url_spec.rb +85 -0
- data/spec/uploader/versions_spec.rb +275 -0
- metadata +34 -3
- data/spec/uploader_spec.rb +0 -887
data/README.rdoc
CHANGED
@@ -36,9 +36,7 @@ this should give you a file in:
|
|
36
36
|
|
37
37
|
Check out this file for some hints on how you can customize your uploader. It should look something like this:
|
38
38
|
|
39
|
-
class AvatarUploader
|
40
|
-
include CarrierWave::Uploader
|
41
|
-
|
39
|
+
class AvatarUploader < CarrierWave::Uploader::Base
|
42
40
|
storage :file
|
43
41
|
end
|
44
42
|
|
@@ -97,9 +95,7 @@ Now you can cache files by assigning them to the attribute, they will automatica
|
|
97
95
|
|
98
96
|
In order to change where uploaded files are put, just override the +store_dir+ method:
|
99
97
|
|
100
|
-
class MyUploader
|
101
|
-
include CarrierWave::Uploader
|
102
|
-
|
98
|
+
class MyUploader < CarrierWave::Uploader::Base
|
103
99
|
def store_dir
|
104
100
|
'public/my/upload/directory'
|
105
101
|
end
|
@@ -111,10 +107,9 @@ This works for the file storage as well as Amazon S3.
|
|
111
107
|
|
112
108
|
Often you'll want to add different versions of the same file. The classic example is image thumbnails. There is built in support for this:
|
113
109
|
|
114
|
-
class MyUploader
|
115
|
-
include CarrierWave::Uploader
|
110
|
+
class MyUploader < CarrierWave::Uploader::Base
|
116
111
|
include CarrierWave::RMagick
|
117
|
-
|
112
|
+
|
118
113
|
process :resize => [800, 800]
|
119
114
|
|
120
115
|
version :thumb do
|
@@ -135,8 +130,7 @@ One important thing to remember is that process is called *before* versions are
|
|
135
130
|
|
136
131
|
It is possible to nest versions within versions:
|
137
132
|
|
138
|
-
class MyUploader
|
139
|
-
include CarrierWave::Uploader
|
133
|
+
class MyUploader < CarrierWave::Uploader::Base
|
140
134
|
|
141
135
|
version :animal do
|
142
136
|
version :human
|
@@ -174,6 +168,16 @@ in the case of images, a small thumbnail would be a good indicator:
|
|
174
168
|
|
175
169
|
NOTE: this feature currently requires write access to your filesystem. If write access is unavailable (e.g. Heroku) you will not be able to upload files. You can prevent CarrierWave from writing to the file system by setting `CarrierWave.config[:cache_to_cache_dir] = false`. This will however break redisplays of forms.
|
176
170
|
|
171
|
+
== Providing a default path
|
172
|
+
|
173
|
+
In many cases, especially when working with images, it might be a good idea to provide a default path, a fallback in case no file has been uploaded. You can do this easily by overriding the +default_path+ method in your uploader:
|
174
|
+
|
175
|
+
class MyUploader < CarrierWave::Uploader::Base
|
176
|
+
def default_path
|
177
|
+
"images/fallback/" + [version_name, "default.png"].compact.join('_')
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
177
181
|
== Using Amazon S3
|
178
182
|
|
179
183
|
You'll need to configure a bucket, access id and secret key like this:
|
@@ -186,9 +190,7 @@ Do this in an initializer in Rails, and in a +before_app_loads+ block in Merb.
|
|
186
190
|
|
187
191
|
And then in your uploader, set the storage to :s3
|
188
192
|
|
189
|
-
class AvatarUploader
|
190
|
-
include CarrierWave::Uploader
|
191
|
-
|
193
|
+
class AvatarUploader <
|
192
194
|
storage :s3
|
193
195
|
end
|
194
196
|
|
@@ -198,15 +200,13 @@ That's it! You can still use the +CarrierWave::Uploader#url+ method to return th
|
|
198
200
|
|
199
201
|
If you're uploading images, you'll probably want to manipulate them in some way, you might want to create thumbnail images for example. CarrierWave comes with a small library to make manipulating images with RMagick easier, you'll need to include it in your Uploader:
|
200
202
|
|
201
|
-
class AvatarUploader
|
202
|
-
include CarrierWave::Uploader
|
203
|
+
class AvatarUploader < CarrierWave::Uploader::Base
|
203
204
|
include CarrierWave::RMagick
|
204
205
|
end
|
205
206
|
|
206
207
|
The RMagick module gives you a few methods, like +CarrierWave::RMagick#crop_resized+ which manipulate the image file in some way. You can set a +process+ callback, which will call that method any time a file is uploaded.
|
207
208
|
|
208
|
-
class AvatarUploader
|
209
|
-
include CarrierWave::Uploader
|
209
|
+
class AvatarUploader < CarrierWave::Uploader::Base
|
210
210
|
include CarrierWave::RMagick
|
211
211
|
|
212
212
|
process :crop_resized => [200, 200]
|
@@ -223,13 +223,28 @@ Check out the manipulate! method, which makes it easy for you to write your own
|
|
223
223
|
|
224
224
|
ImageScience works the same way as RMagick.
|
225
225
|
|
226
|
-
class AvatarUploader
|
227
|
-
include CarrierWave::Uploader
|
226
|
+
class AvatarUploader < CarrierWave::Uploader::Base
|
228
227
|
include CarrierWave::ImageScience
|
229
228
|
|
230
229
|
process :crop_resized => [200, 200]
|
231
230
|
end
|
232
231
|
|
232
|
+
== Migrating
|
233
|
+
|
234
|
+
If you are using Paperclip, you can use the provided compatibility module:
|
235
|
+
|
236
|
+
class AvatarUploader < CarrierWave::Uploader::Base
|
237
|
+
include CarrierWave::Compatibility::Paperclip
|
238
|
+
end
|
239
|
+
|
240
|
+
See the documentation for +Paperclip::Compatibility::Paperclip+ for more detaills.
|
241
|
+
|
242
|
+
Be sure to use mount_on to specify the correct column:
|
243
|
+
|
244
|
+
mount_uploader :avatar, AvatarUploader, :mount_on => :avatar_file_name
|
245
|
+
|
246
|
+
Unfortunately AttachmentFoo differs too much in philosophy for there to be a sensible compatibility mode. Patches for migrating from other solutions will be happily accepted.
|
247
|
+
|
233
248
|
== Documentation
|
234
249
|
|
235
250
|
Full rdoc documentation is {available at Rubyforge}[http://carrierwave.rubyforge.org/].
|
data/Rakefile
CHANGED
@@ -0,0 +1,91 @@
|
|
1
|
+
# This file contains code taken from Paperclip
|
2
|
+
#
|
3
|
+
# LICENSE
|
4
|
+
#
|
5
|
+
# The MIT License
|
6
|
+
#
|
7
|
+
# Copyright (c) 2008 Jon Yurek and thoughtbot, inc.
|
8
|
+
#
|
9
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
10
|
+
# of this software and associated documentation files (the "Software"), to deal
|
11
|
+
# in the Software without restriction, including without limitation the rights
|
12
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
13
|
+
# copies of the Software, and to permit persons to whom the Software is
|
14
|
+
# furnished to do so, subject to the following conditions:
|
15
|
+
#
|
16
|
+
# The above copyright notice and this permission notice shall be included in
|
17
|
+
# all copies or substantial portions of the Software.
|
18
|
+
#
|
19
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
20
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
21
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
22
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
23
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
24
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
25
|
+
# THE SOFTWARE.
|
26
|
+
|
27
|
+
module CarrierWave
|
28
|
+
module Compatibility
|
29
|
+
|
30
|
+
##
|
31
|
+
# Mix this module into an Uploader to make it mimic Paperclip's storage paths
|
32
|
+
# This will make your Uploader use the same default storage path as paperclip
|
33
|
+
# does. If you need to override it, you can override the +paperclip_path+ method
|
34
|
+
# and provide a Paperclip style path:
|
35
|
+
#
|
36
|
+
# class MyUploader < CarrierWave::Uploader::Base
|
37
|
+
# include CarrierWave::Compatibility::Paperclip
|
38
|
+
#
|
39
|
+
# def paperclip_path
|
40
|
+
# ":rails_root/public/uploads/:id/:attachment/:style_:basename.:extension"
|
41
|
+
# end
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
module Paperclip
|
45
|
+
|
46
|
+
def store_path(for_file=filename)
|
47
|
+
path = paperclip_path
|
48
|
+
path ||= File.join(*[store_dir, paperclip_style.to_s, for_file].compact)
|
49
|
+
interpolate_paperclip_path(path, for_file)
|
50
|
+
end
|
51
|
+
|
52
|
+
def store_dir
|
53
|
+
":rails_root/public/system/:attachment/:id"
|
54
|
+
end
|
55
|
+
|
56
|
+
def paperclip_default_style
|
57
|
+
:original
|
58
|
+
end
|
59
|
+
|
60
|
+
def paperclip_path
|
61
|
+
end
|
62
|
+
|
63
|
+
def paperclip_style
|
64
|
+
version_name || paperclip_default_style
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def interpolate_paperclip_path(path, filename)
|
70
|
+
mappings.inject(path) do |agg, pair|
|
71
|
+
agg.gsub(":#{pair[0]}", pair[1].call(self, filename).to_s)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def mappings
|
76
|
+
{
|
77
|
+
:rails_root => lambda{|u, f| CarrierWave.config[:root] },
|
78
|
+
:rails_env => lambda{|u, f| CarrierWave.config[:env] },
|
79
|
+
:class => lambda{|u, f| u.model.class.name.underscore.pluralize},
|
80
|
+
:id => lambda{|u, f| u.model.id },
|
81
|
+
:id_partition => lambda{|u, f| ("%09d" % u.model.id).scan(/\d{3}/).join("/")},
|
82
|
+
:attachment => lambda{|u, f| u.mounted_as.to_s.downcase.pluralize },
|
83
|
+
:style => lambda{|u, f| u.paperclip_style },
|
84
|
+
:basename => lambda{|u, f| f.gsub(/#{File.extname(f)}$/, "") },
|
85
|
+
:extension => lambda{|u, f| File.extname(f).gsub(/^\.+/, "")}
|
86
|
+
}
|
87
|
+
end
|
88
|
+
|
89
|
+
end # Paperclip
|
90
|
+
end # Compatibility
|
91
|
+
end # CarrierWave
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# Stolen from Rails 3
|
2
|
+
|
3
|
+
# Copyright (c) 2005-2009 David Heinemeier Hansson
|
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.
|
23
|
+
|
24
|
+
# Retain for backward compatibility. Methods are now included in Class.
|
25
|
+
class Class
|
26
|
+
# Defines class-level inheritable attribute reader. Attributes are available to subclasses,
|
27
|
+
# each subclass has a copy of parent's attribute.
|
28
|
+
#
|
29
|
+
# @param *syms<Array[#to_s]> Array of attributes to define inheritable reader for.
|
30
|
+
# @return <Array[#to_s]> Array of attributes converted into inheritable_readers.
|
31
|
+
#
|
32
|
+
# @api public
|
33
|
+
#
|
34
|
+
# @todo Do we want to block instance_reader via :instance_reader => false
|
35
|
+
# @todo It would be preferable that we do something with a Hash passed in
|
36
|
+
# (error out or do the same as other methods above) instead of silently
|
37
|
+
# moving on). In particular, this makes the return value of this function
|
38
|
+
# less useful.
|
39
|
+
def extlib_inheritable_reader(*ivars)
|
40
|
+
instance_reader = ivars.pop[:reader] if ivars.last.is_a?(Hash)
|
41
|
+
|
42
|
+
ivars.each do |ivar|
|
43
|
+
self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
44
|
+
def self.#{ivar}
|
45
|
+
return @#{ivar} if self.object_id == #{self.object_id} || defined?(@#{ivar})
|
46
|
+
ivar = superclass.#{ivar}
|
47
|
+
return nil if ivar.nil? && !#{self}.instance_variable_defined?("@#{ivar}")
|
48
|
+
@#{ivar} = ivar && !ivar.is_a?(Module) && !ivar.is_a?(Numeric) && !ivar.is_a?(TrueClass) && !ivar.is_a?(FalseClass) ? ivar.dup : ivar
|
49
|
+
end
|
50
|
+
RUBY
|
51
|
+
unless instance_reader == false
|
52
|
+
self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
53
|
+
def #{ivar}
|
54
|
+
self.class.#{ivar}
|
55
|
+
end
|
56
|
+
RUBY
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Defines class-level inheritable attribute writer. Attributes are available to subclasses,
|
62
|
+
# each subclass has a copy of parent's attribute.
|
63
|
+
#
|
64
|
+
# @param *syms<Array[*#to_s, Hash{:instance_writer => Boolean}]> Array of attributes to
|
65
|
+
# define inheritable writer for.
|
66
|
+
# @option syms :instance_writer<Boolean> if true, instance-level inheritable attribute writer is defined.
|
67
|
+
# @return <Array[#to_s]> An Array of the attributes that were made into inheritable writers.
|
68
|
+
#
|
69
|
+
# @api public
|
70
|
+
#
|
71
|
+
# @todo We need a style for class_eval <<-HEREDOC. I'd like to make it
|
72
|
+
# class_eval(<<-RUBY, __FILE__, __LINE__), but we should codify it somewhere.
|
73
|
+
def extlib_inheritable_writer(*ivars)
|
74
|
+
instance_writer = ivars.pop[:writer] if ivars.last.is_a?(Hash)
|
75
|
+
ivars.each do |ivar|
|
76
|
+
self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
77
|
+
def self.#{ivar}=(obj)
|
78
|
+
@#{ivar} = obj
|
79
|
+
end
|
80
|
+
RUBY
|
81
|
+
unless instance_writer == false
|
82
|
+
self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
83
|
+
def #{ivar}=(obj) self.class.#{ivar} = obj end
|
84
|
+
RUBY
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# Defines class-level inheritable attribute accessor. Attributes are available to subclasses,
|
90
|
+
# each subclass has a copy of parent's attribute.
|
91
|
+
#
|
92
|
+
# @param *syms<Array[*#to_s, Hash{:instance_writer => Boolean}]> Array of attributes to
|
93
|
+
# define inheritable accessor for.
|
94
|
+
# @option syms :instance_writer<Boolean> if true, instance-level inheritable attribute writer is defined.
|
95
|
+
# @return <Array[#to_s]> An Array of attributes turned into inheritable accessors.
|
96
|
+
#
|
97
|
+
# @api public
|
98
|
+
def extlib_inheritable_accessor(*syms)
|
99
|
+
extlib_inheritable_reader(*syms)
|
100
|
+
extlib_inheritable_writer(*syms)
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# Stolen from Rails 3
|
2
|
+
|
3
|
+
# Copyright (c) 2005-2009 David Heinemeier Hansson
|
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.
|
23
|
+
|
24
|
+
class Module
|
25
|
+
attr_accessor :_setup_block
|
26
|
+
attr_accessor :_dependencies
|
27
|
+
|
28
|
+
def setup(&blk)
|
29
|
+
@_setup_block = blk
|
30
|
+
end
|
31
|
+
|
32
|
+
def use(mod)
|
33
|
+
return if self < mod
|
34
|
+
|
35
|
+
(mod._dependencies || []).each do |dep|
|
36
|
+
use dep
|
37
|
+
end
|
38
|
+
# raise "Circular dependencies" if self < mod
|
39
|
+
include mod
|
40
|
+
extend mod.const_get("ClassMethods") if mod.const_defined?("ClassMethods")
|
41
|
+
class_eval(&mod._setup_block) if mod._setup_block
|
42
|
+
end
|
43
|
+
|
44
|
+
def depends_on(mod)
|
45
|
+
return if self < mod
|
46
|
+
@_dependencies ||= []
|
47
|
+
@_dependencies << mod
|
48
|
+
end
|
49
|
+
end
|
data/lib/carrierwave/mount.rb
CHANGED
@@ -70,6 +70,7 @@ module CarrierWave
|
|
70
70
|
# [remove_image?] Whether the file should be removed when store_image! is called.
|
71
71
|
#
|
72
72
|
# [store_image!] Stores a file that has been assigned with +image=+
|
73
|
+
# [remove_image!] Removes the uploaded file from the filesystem.
|
73
74
|
#
|
74
75
|
# [image_integrity_error] Returns an error object if the last file to be assigned caused an integrty error
|
75
76
|
# [image_processing_error] Returns an error object if the last file to be assigned caused a processing error
|
@@ -115,9 +116,7 @@ module CarrierWave
|
|
115
116
|
#
|
116
117
|
def mount_uploader(column, uploader=nil, options={}, &block)
|
117
118
|
unless uploader
|
118
|
-
uploader = Class.new
|
119
|
-
include CarrierWave::Uploader
|
120
|
-
end
|
119
|
+
uploader = Class.new(CarrierWave::Uploader::Base)
|
121
120
|
uploader.class_eval(&block)
|
122
121
|
end
|
123
122
|
|
@@ -127,58 +126,68 @@ module CarrierWave
|
|
127
126
|
include CarrierWave::Mount::Extension
|
128
127
|
|
129
128
|
class_eval <<-RUBY, __FILE__, __LINE__+1
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
129
|
+
|
130
|
+
def #{column}
|
131
|
+
_mounter(:#{column}).uploader
|
132
|
+
end
|
133
|
+
|
134
|
+
def #{column}=(new_file)
|
135
|
+
_mounter(:#{column}).cache(new_file)
|
136
|
+
end
|
137
|
+
|
138
|
+
def #{column}?
|
139
|
+
!_mounter(:#{column}).blank?
|
140
|
+
end
|
141
|
+
|
142
|
+
def #{column}_url(*args)
|
143
|
+
_mounter(:#{column}).url(*args)
|
144
|
+
end
|
145
|
+
|
146
|
+
def #{column}_uploader
|
147
|
+
_mounter(:#{column}).uploader
|
148
|
+
end
|
149
|
+
|
150
|
+
def #{column}_uploader=(uploader)
|
151
|
+
_mounter(:#{column}).uploader = uploader
|
152
|
+
end
|
153
|
+
|
154
|
+
def #{column}_cache
|
155
|
+
_mounter(:#{column}).cache_name
|
156
|
+
end
|
157
|
+
|
158
|
+
def #{column}_cache=(cache_name)
|
159
|
+
_mounter(:#{column}).cache_name = cache_name
|
160
|
+
end
|
161
|
+
|
162
|
+
def remove_#{column}
|
163
|
+
_mounter(:#{column}).remove
|
164
|
+
end
|
165
|
+
|
166
|
+
def remove_#{column}!
|
167
|
+
_mounter(:#{column}).remove!
|
168
|
+
end
|
169
|
+
|
170
|
+
def remove_#{column}=(value)
|
171
|
+
_mounter(:#{column}).remove = value
|
172
|
+
end
|
173
|
+
|
174
|
+
def remove_#{column}?
|
175
|
+
_mounter(:#{column}).remove?
|
176
|
+
end
|
177
|
+
|
178
|
+
def store_#{column}!
|
179
|
+
_mounter(:#{column}).store!
|
180
|
+
end
|
181
|
+
|
182
|
+
def #{column}_integrity_error
|
183
|
+
_mounter(:#{column}).integrity_error
|
184
|
+
end
|
185
|
+
|
186
|
+
def #{column}_processing_error
|
187
|
+
_mounter(:#{column}).processing_error
|
188
|
+
end
|
181
189
|
RUBY
|
190
|
+
|
182
191
|
end
|
183
192
|
|
184
193
|
module Extension
|
@@ -195,85 +204,92 @@ module CarrierWave
|
|
195
204
|
|
196
205
|
private
|
197
206
|
|
198
|
-
def
|
199
|
-
@
|
200
|
-
@
|
207
|
+
def _mounter(column)
|
208
|
+
@_mounters ||= {}
|
209
|
+
@_mounters[column] ||= Mounter.new(self, column)
|
201
210
|
end
|
202
211
|
|
203
|
-
|
204
|
-
@_uploaders ||= {}
|
205
|
-
@_uploaders[column] = uploader
|
206
|
-
end
|
212
|
+
end # Extension
|
207
213
|
|
208
|
-
|
209
|
-
|
210
|
-
|
214
|
+
# this is an internal class, used by CarrierWave::Mount so that
|
215
|
+
# we don't pollute the model with a lot of methods.
|
216
|
+
class Mounter #:nodoc:
|
217
|
+
|
218
|
+
attr_reader :column, :record, :options
|
211
219
|
|
212
|
-
|
213
|
-
return _uploader_get(column) unless _uploader_get(column).blank?
|
220
|
+
attr_accessor :uploader, :integrity_error, :processing_error, :remove
|
214
221
|
|
215
|
-
|
222
|
+
def initialize(record, column, options={})
|
223
|
+
@record = record
|
224
|
+
@column = column
|
225
|
+
@options = record.class.uploader_options[column]
|
226
|
+
end
|
216
227
|
|
217
|
-
|
218
|
-
|
219
|
-
|
228
|
+
def uploader
|
229
|
+
@uploader ||= record.class.uploaders[column].new(record, column)
|
230
|
+
if @uploader.blank?
|
231
|
+
identifier = record.read_uploader(serialization_column)
|
232
|
+
@uploader.retrieve_from_store!(identifier) unless identifier.blank?
|
220
233
|
end
|
234
|
+
return @uploader
|
221
235
|
end
|
222
236
|
|
223
|
-
def
|
224
|
-
|
225
|
-
|
226
|
-
|
237
|
+
def cache(new_file)
|
238
|
+
uploader.cache!(new_file)
|
239
|
+
self.integrity_error = nil
|
240
|
+
self.processing_error = nil
|
227
241
|
rescue CarrierWave::IntegrityError => e
|
228
|
-
|
229
|
-
raise e unless
|
242
|
+
self.integrity_error = e
|
243
|
+
raise e unless options[:ignore_integrity_errors]
|
230
244
|
rescue CarrierWave::ProcessingError => e
|
231
|
-
|
232
|
-
raise e unless
|
233
|
-
end
|
234
|
-
|
235
|
-
def _uploader_get_url(column, *args)
|
236
|
-
_uploader_get_column(column)
|
237
|
-
_uploader_get(column).url(*args)
|
245
|
+
self.processing_error = e
|
246
|
+
raise e unless options[:ignore_processing_errors]
|
238
247
|
end
|
239
248
|
|
240
|
-
def
|
241
|
-
|
249
|
+
def cache_name
|
250
|
+
uploader.cache_name
|
242
251
|
end
|
243
252
|
|
244
|
-
def
|
245
|
-
|
253
|
+
def cache_name=(cache_name)
|
254
|
+
uploader.retrieve_from_cache!(cache_name) unless uploader.cached?
|
255
|
+
rescue CarrierWave::InvalidParameter
|
246
256
|
end
|
247
257
|
|
248
|
-
def
|
249
|
-
unless
|
250
|
-
if
|
251
|
-
|
252
|
-
write_uploader(
|
258
|
+
def store!
|
259
|
+
unless uploader.blank?
|
260
|
+
if remove?
|
261
|
+
uploader.remove!
|
262
|
+
record.write_uploader(serialization_column, '')
|
253
263
|
else
|
254
|
-
|
255
|
-
write_uploader(
|
264
|
+
uploader.store!
|
265
|
+
record.write_uploader(serialization_column, uploader.identifier)
|
256
266
|
end
|
257
267
|
end
|
258
268
|
end
|
259
269
|
|
260
|
-
def
|
261
|
-
|
270
|
+
def url(*args)
|
271
|
+
uploader.url(*args)
|
262
272
|
end
|
263
273
|
|
264
|
-
def
|
265
|
-
|
274
|
+
def blank?
|
275
|
+
uploader.blank?
|
266
276
|
end
|
267
277
|
|
268
|
-
def
|
269
|
-
|
278
|
+
def remove?
|
279
|
+
!remove.blank? and remove !~ /\A0|false$\z/
|
270
280
|
end
|
271
281
|
|
272
|
-
def
|
273
|
-
|
282
|
+
def remove!
|
283
|
+
uploader.remove!
|
274
284
|
end
|
275
285
|
|
276
|
-
|
286
|
+
private
|
287
|
+
|
288
|
+
def serialization_column
|
289
|
+
options[:mount_on] || column
|
290
|
+
end
|
291
|
+
|
292
|
+
end # Mounter
|
277
293
|
|
278
294
|
end # Mount
|
279
295
|
end # CarrierWave
|
@@ -17,7 +17,12 @@ module CarrierWave
|
|
17
17
|
validates_integrity_of column if uploader_options[column.to_sym][:validate_integrity]
|
18
18
|
validates_processing_of column if uploader_options[column.to_sym][:validate_processing]
|
19
19
|
|
20
|
-
|
20
|
+
after_create do |record|
|
21
|
+
record.send("store_#{column}!")
|
22
|
+
record.save
|
23
|
+
end
|
24
|
+
|
25
|
+
before_update do |record|
|
21
26
|
record.send("store_#{column}!")
|
22
27
|
end
|
23
28
|
end
|