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.
Files changed (46) hide show
  1. data/README.rdoc +35 -20
  2. data/Rakefile +1 -1
  3. data/lib/carrierwave/compatibility/paperclip.rb +91 -0
  4. data/lib/carrierwave/core_ext/inheritable_attributes.rb +102 -0
  5. data/lib/carrierwave/core_ext/module_setup.rb +49 -0
  6. data/lib/carrierwave/mount.rb +119 -103
  7. data/lib/carrierwave/orm/activerecord.rb +6 -1
  8. data/lib/carrierwave/orm/sequel.rb +15 -2
  9. data/lib/carrierwave/processing/rmagick.rb +8 -7
  10. data/lib/carrierwave/storage/abstract.rb +16 -1
  11. data/lib/carrierwave/storage/file.rb +20 -1
  12. data/lib/carrierwave/uploader/cache.rb +114 -0
  13. data/lib/carrierwave/uploader/callbacks.rb +40 -0
  14. data/lib/carrierwave/uploader/default_path.rb +21 -0
  15. data/lib/carrierwave/uploader/extension_whitelist.rb +35 -0
  16. data/lib/carrierwave/uploader/mountable.rb +37 -0
  17. data/lib/carrierwave/uploader/paths.rb +25 -0
  18. data/lib/carrierwave/uploader/processing.rb +79 -0
  19. data/lib/carrierwave/uploader/proxy.rb +60 -0
  20. data/lib/carrierwave/uploader/remove.rb +21 -0
  21. data/lib/carrierwave/uploader/store.rb +154 -0
  22. data/lib/carrierwave/uploader/url.rb +22 -0
  23. data/lib/carrierwave/uploader/versions.rb +145 -0
  24. data/lib/carrierwave/uploader.rb +31 -593
  25. data/lib/carrierwave.rb +55 -7
  26. data/lib/generators/uploader_generator.rb +1 -1
  27. data/rails_generators/uploader/templates/uploader.rb +12 -8
  28. data/spec/compatibility/paperclip_spec.rb +41 -0
  29. data/spec/mount_spec.rb +88 -25
  30. data/spec/orm/activerecord_spec.rb +7 -9
  31. data/spec/orm/datamapper_spec.rb +7 -9
  32. data/spec/orm/sequel_spec.rb +47 -32
  33. data/spec/spec_helper.rb +13 -0
  34. data/spec/uploader/cache_spec.rb +194 -0
  35. data/spec/uploader/default_path_spec.rb +66 -0
  36. data/spec/uploader/extension_whitelist_spec.rb +42 -0
  37. data/spec/uploader/mountable_spec.rb +31 -0
  38. data/spec/uploader/paths_spec.rb +20 -0
  39. data/spec/uploader/processing_spec.rb +60 -0
  40. data/spec/uploader/proxy_spec.rb +52 -0
  41. data/spec/uploader/remove_spec.rb +65 -0
  42. data/spec/uploader/store_spec.rb +260 -0
  43. data/spec/uploader/url_spec.rb +85 -0
  44. data/spec/uploader/versions_spec.rb +275 -0
  45. metadata +34 -3
  46. 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
@@ -9,7 +9,7 @@ require 'spec/rake/spectask'
9
9
  require 'cucumber/rake/task'
10
10
 
11
11
  NAME = "carrierwave"
12
- GEM_VERSION = "0.2.2"
12
+ GEM_VERSION = "0.2.3"
13
13
  AUTHOR = "Jonas Nicklas"
14
14
  EMAIL = "jonas.nicklas@gmail.com"
15
15
  HOMEPAGE = "http://www.example.com"
@@ -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
@@ -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 do
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
- def #{column}_uploader # def image_uploader
131
- _uploader_get(:#{column}) # _uploader_get(:image)
132
- end # end
133
- #
134
- def #{column}_uploader=(uploader) # def image_uploader=(uploader)
135
- _uploader_set(:#{column}, uploader) # _uploader_set(:image, uploader)
136
- end # end
137
- #
138
- def #{column}_url(*args) # def image_url(*args)
139
- _uploader_get_url(:#{column}, *args) # _uploader_get_url(:image, *args)
140
- end # end
141
- #
142
- def #{column} # def image
143
- _uploader_get_column(:#{column}) # _uploader_get_column(:image)
144
- end # end
145
- #
146
- def #{column}=(new_file) # def image=(new_file)
147
- _uploader_set_column(:#{column}, new_file) # _uploader_set_column(:image, new_file)
148
- end # end
149
- #
150
- def #{column}_cache # def image_cache
151
- _uploader_get_cache(:#{column}) # _uploader_get_cache(:image)
152
- end # end
153
- #
154
- def #{column}_cache=(cache_name) # def image_cache=(cache_name)
155
- _uploader_set_cache(:#{column}, cache_name) # _uploader_set_cache(:image, cache_name)
156
- end # end
157
- #
158
- def remove_#{column} # def remove_image
159
- _uploader_remove[:#{column}] # _uploader_remove[:image]
160
- end # end
161
- #
162
- def remove_#{column}=(value) # def remove_image=(value)
163
- _uploader_remove[:#{column}] = value # _uploader_remove[:image] = value
164
- end # end
165
- #
166
- def remove_#{column}? # def remove_image?
167
- _uploader_remove?(:#{column}) # _uploader_remove?(:image)
168
- end # end
169
- #
170
- def store_#{column}! # def store_image!
171
- _uploader_store!(:#{column}) # _uploader_store!(:image)
172
- end # end
173
- #
174
- def #{column}_integrity_error # def image_integrity_error
175
- _uploader_integrity_errors[:#{column}] # _uploader_integrity_errors[:image]
176
- end # end
177
- #
178
- def #{column}_processing_error # def image_processing_error
179
- _uploader_processing_errors[:#{column}] # _uploader_processing_errors[:image]
180
- end # end
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 _uploader_get(column)
199
- @_uploaders ||= {}
200
- @_uploaders[column] ||= self.class.uploaders[column].new(self, column)
207
+ def _mounter(column)
208
+ @_mounters ||= {}
209
+ @_mounters[column] ||= Mounter.new(self, column)
201
210
  end
202
211
 
203
- def _uploader_set(column, uploader)
204
- @_uploaders ||= {}
205
- @_uploaders[column] = uploader
206
- end
212
+ end # Extension
207
213
 
208
- def _uploader_options(column)
209
- self.class.uploader_options[column]
210
- end
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
- def _uploader_get_column(column)
213
- return _uploader_get(column) unless _uploader_get(column).blank?
220
+ attr_accessor :uploader, :integrity_error, :processing_error, :remove
214
221
 
215
- identifier = read_uploader(_uploader_options(column)[:mount_on] || column)
222
+ def initialize(record, column, options={})
223
+ @record = record
224
+ @column = column
225
+ @options = record.class.uploader_options[column]
226
+ end
216
227
 
217
- unless identifier.blank?
218
- _uploader_get(column).retrieve_from_store!(identifier)
219
- _uploader_get(column)
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 _uploader_set_column(column, new_file)
224
- _uploader_get(column).cache!(new_file)
225
- _uploader_integrity_errors[column] = nil
226
- _uploader_processing_errors[column] = nil
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
- _uploader_integrity_errors[column] = e
229
- raise e unless _uploader_options(column)[:ignore_integrity_errors]
242
+ self.integrity_error = e
243
+ raise e unless options[:ignore_integrity_errors]
230
244
  rescue CarrierWave::ProcessingError => e
231
- _uploader_processing_errors[column] = e
232
- raise e unless _uploader_options(column)[:ignore_processing_errors]
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 _uploader_get_cache(column)
241
- _uploader_get(column).cache_name
249
+ def cache_name
250
+ uploader.cache_name
242
251
  end
243
252
 
244
- def _uploader_set_cache(column, cache_name)
245
- _uploader_get(column).retrieve_from_cache(cache_name) unless cache_name.blank?
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 _uploader_store!(column)
249
- unless _uploader_get(column).blank?
250
- if _uploader_remove?(column)
251
- _uploader_set(column, nil)
252
- write_uploader(column, '')
258
+ def store!
259
+ unless uploader.blank?
260
+ if remove?
261
+ uploader.remove!
262
+ record.write_uploader(serialization_column, '')
253
263
  else
254
- _uploader_get(column).store!
255
- write_uploader(_uploader_options(column)[:mount_on] || column, _uploader_get(column).identifier)
264
+ uploader.store!
265
+ record.write_uploader(serialization_column, uploader.identifier)
256
266
  end
257
267
  end
258
268
  end
259
269
 
260
- def _uploader_remove
261
- @_uploader_remove ||= {}
270
+ def url(*args)
271
+ uploader.url(*args)
262
272
  end
263
273
 
264
- def _uploader_remove?(column)
265
- !_uploader_remove[column].blank? and _uploader_remove[column] !~ /\A0|false$\z/
274
+ def blank?
275
+ uploader.blank?
266
276
  end
267
277
 
268
- def _uploader_integrity_errors
269
- @_uploader_integrity_errors ||= {}
278
+ def remove?
279
+ !remove.blank? and remove !~ /\A0|false$\z/
270
280
  end
271
281
 
272
- def _uploader_processing_errors
273
- @_uploader_processing_errors ||= {}
282
+ def remove!
283
+ uploader.remove!
274
284
  end
275
285
 
276
- end # Extension
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
- before_save do |record|
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