carrierwave 0.11.2 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of carrierwave might be problematic. Click here for more details.

Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +215 -116
  3. data/lib/carrierwave/compatibility/paperclip.rb +0 -2
  4. data/lib/carrierwave/error.rb +1 -0
  5. data/lib/carrierwave/locale/en.yml +7 -4
  6. data/lib/carrierwave/mount.rb +217 -176
  7. data/lib/carrierwave/mounter.rb +164 -0
  8. data/lib/carrierwave/orm/activerecord.rb +49 -20
  9. data/lib/carrierwave/processing/mini_magick.rb +64 -13
  10. data/lib/carrierwave/processing/rmagick.rb +31 -3
  11. data/lib/carrierwave/processing.rb +0 -1
  12. data/lib/carrierwave/sanitized_file.rb +43 -38
  13. data/lib/carrierwave/storage/abstract.rb +15 -2
  14. data/lib/carrierwave/storage/file.rb +65 -2
  15. data/lib/carrierwave/storage/fog.rb +101 -27
  16. data/lib/carrierwave/storage.rb +0 -9
  17. data/lib/carrierwave/test/matchers.rb +77 -12
  18. data/lib/carrierwave/uploader/cache.rb +40 -26
  19. data/lib/carrierwave/uploader/callbacks.rb +0 -2
  20. data/lib/carrierwave/uploader/configuration.rb +48 -6
  21. data/lib/carrierwave/uploader/default_url.rb +3 -5
  22. data/lib/carrierwave/uploader/download.rb +10 -7
  23. data/lib/carrierwave/uploader/extension_blacklist.rb +14 -10
  24. data/lib/carrierwave/uploader/extension_whitelist.rb +12 -10
  25. data/lib/carrierwave/uploader/file_size.rb +41 -0
  26. data/lib/carrierwave/uploader/magic_mime_blacklist.rb +94 -0
  27. data/lib/carrierwave/uploader/magic_mime_whitelist.rb +94 -0
  28. data/lib/carrierwave/uploader/mountable.rb +7 -8
  29. data/lib/carrierwave/uploader/processing.rb +1 -3
  30. data/lib/carrierwave/uploader/proxy.rb +5 -7
  31. data/lib/carrierwave/uploader/remove.rb +0 -2
  32. data/lib/carrierwave/uploader/serialization.rb +1 -3
  33. data/lib/carrierwave/uploader/store.rb +5 -23
  34. data/lib/carrierwave/uploader/url.rb +1 -3
  35. data/lib/carrierwave/uploader/versions.rb +75 -82
  36. data/lib/carrierwave/uploader.rb +2 -2
  37. data/lib/carrierwave/utilities/uri.rb +4 -7
  38. data/lib/carrierwave/utilities.rb +0 -3
  39. data/lib/carrierwave/validations/active_model.rb +0 -2
  40. data/lib/carrierwave/version.rb +1 -1
  41. data/lib/carrierwave.rb +8 -10
  42. data/lib/generators/templates/uploader.rb +3 -5
  43. metadata +41 -95
  44. data/lib/carrierwave/locale/cs.yml +0 -11
  45. data/lib/carrierwave/locale/de.yml +0 -11
  46. data/lib/carrierwave/locale/el.yml +0 -11
  47. data/lib/carrierwave/locale/es.yml +0 -11
  48. data/lib/carrierwave/locale/fr.yml +0 -11
  49. data/lib/carrierwave/locale/ja.yml +0 -11
  50. data/lib/carrierwave/locale/nb.yml +0 -11
  51. data/lib/carrierwave/locale/nl.yml +0 -11
  52. data/lib/carrierwave/locale/pl.yml +0 -11
  53. data/lib/carrierwave/locale/pt-BR.yml +0 -11
  54. data/lib/carrierwave/locale/pt-PT.yml +0 -11
  55. data/lib/carrierwave/locale/ru.yml +0 -11
  56. data/lib/carrierwave/locale/sk.yml +0 -11
  57. data/lib/carrierwave/locale/tr.yml +0 -11
  58. data/lib/carrierwave/processing/mime_types.rb +0 -74
  59. data/lib/carrierwave/utilities/deprecation.rb +0 -18
@@ -4,8 +4,11 @@ en:
4
4
  carrierwave_processing_error: failed to be processed
5
5
  carrierwave_integrity_error: is not of an allowed file type
6
6
  carrierwave_download_error: could not be downloaded
7
- extension_white_list_error: "You are not allowed to upload %{extension} files, allowed types: %{allowed_types}"
8
- extension_black_list_error: "You are not allowed to upload %{extension} files, prohibited types: %{prohibited_types}"
9
- rmagick_processing_error: "Failed to manipulate with rmagick, maybe it is not an image? Original Error: %{e}"
10
- mime_types_processing_error: "Failed to process file with MIME::Types, maybe not valid content-type? Original Error: %{e}"
7
+ extension_whitelist_error: "You are not allowed to upload %{extension} files, allowed types: %{allowed_types}"
8
+ extension_blacklist_error: "You are not allowed to upload %{extension} files, prohibited types: %{prohibited_types}"
9
+ content_type_whitelist_error: "You are not allowed to upload %{content_type} files"
10
+ content_type_blacklist_error: "You are not allowed to upload %{content_type} files"
11
+ rmagick_processing_error: "Failed to manipulate with rmagick, maybe it is not an image?"
11
12
  mini_magick_processing_error: "Failed to manipulate with MiniMagick, maybe it is not an image? Original Error: %{e}"
13
+ min_size_error: "File size should be greater than %{min_size}"
14
+ max_size_error: "File size should be less than %{max_size}"
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
-
3
1
  module CarrierWave
4
2
 
5
3
  ##
@@ -62,7 +60,7 @@ module CarrierWave
62
60
  # will create an anonymous uploader class.
63
61
  #
64
62
  # Passing a block makes it possible to customize the uploader. This can be
65
- # convenient for brevity, but if there is any significatnt logic in the
63
+ # convenient for brevity, but if there is any significant logic in the
66
64
  # uploader, you should do the right thing and have it in its own file.
67
65
  #
68
66
  # === Added instance methods
@@ -92,7 +90,6 @@ module CarrierWave
92
90
  # [image_processing_error] Returns an error object if the last file to be assigned caused a processing error
93
91
  # [image_download_error] Returns an error object if the last file to be remotely assigned caused a download error
94
92
  #
95
- # [write_image_identifier] Uses the write_uploader method to set the identifier.
96
93
  # [image_identifier] Reads out the identifier of the file
97
94
  #
98
95
  # === Parameters
@@ -135,56 +132,245 @@ module CarrierWave
135
132
  # end
136
133
  #
137
134
  def mount_uploader(column, uploader=nil, options={}, &block)
138
- include CarrierWave::Mount::Extension
139
-
140
- uploader = build_uploader(uploader, &block)
141
- uploaders[column.to_sym] = uploader
142
- uploader_options[column.to_sym] = options
143
-
144
- # Make sure to write over accessors directly defined on the class.
145
- # Simply super to the included module below.
146
- class_eval <<-RUBY, __FILE__, __LINE__+1
147
- def #{column}; super; end
148
- def #{column}=(new_file); super; end
149
- RUBY
135
+ mount_base(column, uploader, options, &block)
150
136
 
151
- # Mixing this in as a Module instead of class_evaling directly, so we
152
- # can maintain the ability to super to any of these methods from within
153
- # the class.
154
137
  mod = Module.new
155
138
  include mod
156
139
  mod.class_eval <<-RUBY, __FILE__, __LINE__+1
157
140
 
158
141
  def #{column}
159
- _mounter(:#{column}).uploader
142
+ _mounter(:#{column}).uploaders[0] ||= _mounter(:#{column}).blank_uploader
160
143
  end
161
144
 
162
145
  def #{column}=(new_file)
163
- _mounter(:#{column}).cache(new_file)
164
- end
165
-
166
- def #{column}?
167
- _mounter(:#{column}).present?
146
+ _mounter(:#{column}).cache([new_file])
168
147
  end
169
148
 
170
149
  def #{column}_url(*args)
171
- _mounter(:#{column}).url(*args)
150
+ #{column}.url(*args)
172
151
  end
173
152
 
174
153
  def #{column}_cache
175
- _mounter(:#{column}).cache_name
154
+ _mounter(:#{column}).cache_names[0]
176
155
  end
177
156
 
178
157
  def #{column}_cache=(cache_name)
179
- _mounter(:#{column}).cache_name = cache_name
158
+ _mounter(:#{column}).cache_names = [cache_name]
180
159
  end
181
160
 
182
161
  def remote_#{column}_url
183
- _mounter(:#{column}).remote_url
162
+ [_mounter(:#{column}).remote_urls].flatten[0]
184
163
  end
185
164
 
186
165
  def remote_#{column}_url=(url)
187
- _mounter(:#{column}).remote_url = url
166
+ _mounter(:#{column}).remote_urls = [url]
167
+ end
168
+
169
+ def remote_#{column}_request_header=(header)
170
+ _mounter(:#{column}).remote_request_headers = [header]
171
+ end
172
+
173
+ def write_#{column}_identifier
174
+ return if frozen?
175
+ mounter = _mounter(:#{column})
176
+
177
+ if mounter.remove?
178
+ write_uploader(mounter.serialization_column, nil)
179
+ elsif mounter.identifiers.first
180
+ write_uploader(mounter.serialization_column, mounter.identifiers.first)
181
+ end
182
+ end
183
+
184
+ def #{column}_identifier
185
+ _mounter(:#{column}).read_identifiers[0]
186
+ end
187
+
188
+ def store_previous_changes_for_#{column}
189
+ @_previous_changes_for_#{column} = changes[_mounter(:#{column}).serialization_column]
190
+ end
191
+
192
+ def remove_previously_stored_#{column}
193
+ before, after = @_previous_changes_for_#{column}
194
+ _mounter(:#{column}).remove_previous([before], [after])
195
+ end
196
+ RUBY
197
+ end
198
+
199
+ ##
200
+ # Mounts the given uploader on the given array column. This means that
201
+ # assigning and reading from the array column will upload and retrieve
202
+ # multiple files. Supposing that a User class has an uploader mounted on
203
+ # images, and that images can store an array, for example it could be a
204
+ # PostgreSQL JSON column. You can assign and retrieve files like this:
205
+ #
206
+ # @user.images # => []
207
+ # @user.images = [some_file_object]
208
+ # @user.images # => [<Uploader>]
209
+ #
210
+ # @user.images[0].url # => '/some_url.png'
211
+ #
212
+ # It is also possible (but not recommended) to omit the uploader, which
213
+ # will create an anonymous uploader class.
214
+ #
215
+ # Passing a block makes it possible to customize the uploader. This can be
216
+ # convenient for brevity, but if there is any significant logic in the
217
+ # uploader, you should do the right thing and have it in its own file.
218
+ #
219
+ # === Added instance methods
220
+ #
221
+ # Supposing a class has used +mount_uploaders+ to mount an uploader on a column
222
+ # named +images+, in that case the following methods will be added to the class:
223
+ #
224
+ # [images] Returns an array of uploaders for each uploaded file
225
+ # [images=] Caches the given files
226
+ #
227
+ # [images_urls] Returns the urls to the uploaded files
228
+ #
229
+ # [images_cache] Returns a string that identifies the cache location of the files
230
+ # [images_cache=] Retrieves the files from the cache based on the given cache name
231
+ #
232
+ # [remote_image_urls] Returns previously cached remote urls
233
+ # [remote_image_urls=] Retrieve files from the given remote urls
234
+ #
235
+ # [remove_images] An attribute reader that can be used with a checkbox to mark the files for removal
236
+ # [remove_images=] An attribute writer that can be used with a checkbox to mark the files for removal
237
+ # [remove_images?] Whether the files should be removed when store_image! is called.
238
+ #
239
+ # [store_images!] Stores all files that have been assigned with +images=+
240
+ # [remove_images!] Removes the uploaded file from the filesystem.
241
+ #
242
+ # [images_integrity_error] Returns an error object if the last files to be assigned caused an integrity error
243
+ # [images_processing_error] Returns an error object if the last files to be assigned caused a processing error
244
+ # [images_download_error] Returns an error object if the last files to be remotely assigned caused a download error
245
+ #
246
+ # [image_identifiers] Reads out the identifiers of the files
247
+ #
248
+ # === Parameters
249
+ #
250
+ # [column (Symbol)] the attribute to mount this uploader on
251
+ # [uploader (CarrierWave::Uploader)] the uploader class to mount
252
+ # [options (Hash{Symbol => Object})] a set of options
253
+ # [&block (Proc)] customize anonymous uploaders
254
+ #
255
+ # === Options
256
+ #
257
+ # [:mount_on => Symbol] if the name of the column to be serialized to differs you can override it using this option
258
+ # [:ignore_integrity_errors => Boolean] if set to true, integrity errors will result in caching failing silently
259
+ # [:ignore_processing_errors => Boolean] if set to true, processing errors will result in caching failing silently
260
+ #
261
+ # === Examples
262
+ #
263
+ # Mounting uploaders on different columns.
264
+ #
265
+ # class Song
266
+ # mount_uploaders :lyrics, LyricsUploader
267
+ # mount_uploaders :alternative_lyrics, LyricsUploader
268
+ # mount_uploaders :files, SongUploader
269
+ # end
270
+ #
271
+ # This will add an anonymous uploader with only the default settings:
272
+ #
273
+ # class Data
274
+ # mount_uploaders :csv_files
275
+ # end
276
+ #
277
+ # this will add an anonymous uploader overriding the store_dir:
278
+ #
279
+ # class Product
280
+ # mount_uploaders :blueprints do
281
+ # def store_dir
282
+ # 'blueprints'
283
+ # end
284
+ # end
285
+ # end
286
+ #
287
+ def mount_uploaders(column, uploader=nil, options={}, &block)
288
+ mount_base(column, uploader, options, &block)
289
+
290
+ mod = Module.new
291
+ include mod
292
+ mod.class_eval <<-RUBY, __FILE__, __LINE__+1
293
+
294
+ def #{column}
295
+ _mounter(:#{column}).uploaders
296
+ end
297
+
298
+ def #{column}=(new_files)
299
+ _mounter(:#{column}).cache(new_files)
300
+ end
301
+
302
+ def #{column}_urls(*args)
303
+ _mounter(:#{column}).urls(*args)
304
+ end
305
+
306
+ def #{column}_cache
307
+ names = _mounter(:#{column}).cache_names
308
+ names.to_json if names.present?
309
+ end
310
+
311
+ def #{column}_cache=(cache_name)
312
+ _mounter(:#{column}).cache_names = JSON.parse(cache_name) if cache_name.present?
313
+ end
314
+
315
+ def remote_#{column}_urls
316
+ _mounter(:#{column}).remote_urls
317
+ end
318
+
319
+ def remote_#{column}_urls=(urls)
320
+ _mounter(:#{column}).remote_urls = urls
321
+ end
322
+
323
+ def remote_#{column}_request_headers=(headers)
324
+ _mounter(:#{column}).remote_request_headers = headers
325
+ end
326
+
327
+ def write_#{column}_identifier
328
+ return if frozen?
329
+ mounter = _mounter(:#{column})
330
+
331
+ if mounter.remove?
332
+ write_uploader(mounter.serialization_column, nil)
333
+ elsif mounter.identifiers.any?
334
+ write_uploader(mounter.serialization_column, mounter.identifiers)
335
+ end
336
+ end
337
+
338
+ def #{column}_identifiers
339
+ _mounter(:#{column}).read_identifiers
340
+ end
341
+
342
+ def store_previous_changes_for_#{column}
343
+ @_previous_changes_for_#{column} = changes[_mounter(:#{column}).serialization_column]
344
+ end
345
+
346
+ def remove_previously_stored_#{column}
347
+ _mounter(:#{column}).remove_previous(*@_previous_changes_for_#{column})
348
+ end
349
+ RUBY
350
+ end
351
+
352
+ private
353
+
354
+ def mount_base(column, uploader=nil, options={}, &block)
355
+ include CarrierWave::Mount::Extension
356
+
357
+ uploader = build_uploader(uploader, &block)
358
+ uploaders[column.to_sym] = uploader
359
+ uploader_options[column.to_sym] = options
360
+
361
+ # Make sure to write over accessors directly defined on the class.
362
+ # Simply super to the included module below.
363
+ class_eval <<-RUBY, __FILE__, __LINE__+1
364
+ def #{column}; super; end
365
+ def #{column}=(new_file); super; end
366
+ RUBY
367
+
368
+ mod = Module.new
369
+ include mod
370
+ mod.class_eval <<-RUBY, __FILE__, __LINE__+1
371
+
372
+ def #{column}?
373
+ _mounter(:#{column}).present?
188
374
  end
189
375
 
190
376
  def remove_#{column}
@@ -219,47 +405,17 @@ module CarrierWave
219
405
  _mounter(:#{column}).download_error
220
406
  end
221
407
 
222
- def write_#{column}_identifier
223
- _mounter(:#{column}).write_identifier
224
- end
225
-
226
- def #{column}_identifier
227
- _mounter(:#{column}).identifier
228
- end
229
-
230
- def store_previous_model_for_#{column}
231
- serialization_column = _mounter(:#{column}).serialization_column
232
-
233
- if #{column}.remove_previously_stored_files_after_update && send(:"\#{serialization_column}_changed?")
234
- @previous_model_for_#{column} ||= self.find_previous_model_for_#{column}
235
- end
236
- end
237
-
238
- def find_previous_model_for_#{column}
239
- self.class.find(to_key.first)
240
- end
241
-
242
- def remove_previously_stored_#{column}
243
- if @previous_model_for_#{column} && @previous_model_for_#{column}.#{column}.path != #{column}.path
244
- @previous_model_for_#{column}.#{column}.remove!
245
- @previous_model_for_#{column} = nil
246
- end
247
- end
248
-
249
408
  def mark_remove_#{column}_false
250
409
  _mounter(:#{column}).remove = false
251
410
  end
252
-
253
411
  RUBY
254
412
  end
255
413
 
256
- private
257
-
258
414
  def build_uploader(uploader, &block)
259
415
  return uploader if uploader && !block_given?
260
416
 
261
417
  uploader = Class.new(uploader || CarrierWave::Uploader::Base)
262
- const_set("Uploader#{uploader.object_id}".gsub('-', '_'), uploader)
418
+ const_set("Uploader#{uploader.object_id}".tr('-', '_'), uploader)
263
419
 
264
420
  if block_given?
265
421
  uploader.class_eval(&block)
@@ -292,120 +448,5 @@ module CarrierWave
292
448
 
293
449
  end # Extension
294
450
 
295
- # this is an internal class, used by CarrierWave::Mount so that
296
- # we don't pollute the model with a lot of methods.
297
- class Mounter #:nodoc:
298
- attr_reader :column, :record, :remote_url, :integrity_error, :processing_error, :download_error
299
- attr_accessor :remove
300
-
301
- def initialize(record, column, options={})
302
- @record = record
303
- @column = column
304
- @options = record.class.uploader_options[column]
305
- end
306
-
307
- def write_identifier
308
- return if record.frozen?
309
-
310
- if remove?
311
- record.write_uploader(serialization_column, nil)
312
- elsif uploader.identifier.present?
313
- record.write_uploader(serialization_column, uploader.identifier)
314
- end
315
- end
316
-
317
- def identifier
318
- record.read_uploader(serialization_column)
319
- end
320
-
321
- def uploader
322
- @uploader ||= record.class.uploaders[column].new(record, column)
323
- @uploader.retrieve_from_store!(identifier) if @uploader.blank? && identifier.present?
324
-
325
- @uploader
326
- end
327
-
328
- def cache(new_file)
329
- uploader.cache!(new_file)
330
- @integrity_error = nil
331
- @processing_error = nil
332
- rescue CarrierWave::IntegrityError => e
333
- @integrity_error = e
334
- raise e unless option(:ignore_integrity_errors)
335
- rescue CarrierWave::ProcessingError => e
336
- @processing_error = e
337
- raise e unless option(:ignore_processing_errors)
338
- end
339
-
340
- def cache_name
341
- uploader.cache_name
342
- end
343
-
344
- def cache_name=(cache_name)
345
- uploader.retrieve_from_cache!(cache_name) unless uploader.cached?
346
- rescue CarrierWave::InvalidParameter
347
- end
348
-
349
- def remote_url=(url)
350
- return if url.blank?
351
-
352
- @remote_url = url
353
- @download_error = nil
354
- @integrity_error = nil
355
-
356
- uploader.download!(url)
357
-
358
- rescue CarrierWave::DownloadError => e
359
- @download_error = e
360
- raise e unless option(:ignore_download_errors)
361
- rescue CarrierWave::ProcessingError => e
362
- @processing_error = e
363
- raise e unless option(:ignore_processing_errors)
364
- rescue CarrierWave::IntegrityError => e
365
- @integrity_error = e
366
- raise e unless option(:ignore_integrity_errors)
367
- end
368
-
369
- def store!
370
- return if uploader.blank?
371
-
372
- if remove?
373
- uploader.remove!
374
- else
375
- uploader.store!
376
- end
377
- end
378
-
379
- def url(*args)
380
- uploader.url(*args)
381
- end
382
-
383
- def blank?
384
- uploader.blank?
385
- end
386
-
387
- def remove?
388
- remove.present? && remove !~ /\A0|false$\z/
389
- end
390
-
391
- def remove!
392
- uploader.remove!
393
- end
394
-
395
- def serialization_column
396
- option(:mount_on) || column
397
- end
398
-
399
- attr_accessor :uploader_options
400
-
401
- private
402
-
403
- def option(name)
404
- self.uploader_options ||= {}
405
- self.uploader_options[name] ||= record.class.uploader_option(column, name)
406
- end
407
-
408
- end # Mounter
409
-
410
451
  end # Mount
411
452
  end # CarrierWave
@@ -0,0 +1,164 @@
1
+ module CarrierWave
2
+
3
+ # this is an internal class, used by CarrierWave::Mount so that
4
+ # we don't pollute the model with a lot of methods.
5
+ class Mounter #:nodoc:
6
+ attr_reader :column, :record, :remote_urls, :integrity_error,
7
+ :processing_error, :download_error
8
+ attr_accessor :remove, :remote_request_headers
9
+
10
+ def initialize(record, column, options={})
11
+ @record = record
12
+ @column = column
13
+ @options = record.class.uploader_options[column]
14
+ end
15
+
16
+ def uploader_class
17
+ record.class.uploaders[column]
18
+ end
19
+
20
+ def blank_uploader
21
+ uploader_class.new(record, column)
22
+ end
23
+
24
+ def identifiers
25
+ uploaders.map(&:identifier)
26
+ end
27
+
28
+ def read_identifiers
29
+ [record.read_uploader(serialization_column)].flatten.reject(&:blank?)
30
+ end
31
+
32
+ def uploaders
33
+ @uploaders ||= read_identifiers.map do |identifier|
34
+ uploader = blank_uploader
35
+ uploader.retrieve_from_store!(identifier) if identifier.present?
36
+ uploader
37
+ end
38
+ end
39
+
40
+ def cache(new_files)
41
+ return if not new_files or new_files == ""
42
+ @uploaders = new_files.map do |new_file|
43
+ uploader = blank_uploader
44
+ uploader.cache!(new_file)
45
+ uploader
46
+ end
47
+
48
+ @integrity_error = nil
49
+ @processing_error = nil
50
+ rescue CarrierWave::IntegrityError => e
51
+ @integrity_error = e
52
+ raise e unless option(:ignore_integrity_errors)
53
+ rescue CarrierWave::ProcessingError => e
54
+ @processing_error = e
55
+ raise e unless option(:ignore_processing_errors)
56
+ end
57
+
58
+ def cache_names
59
+ uploaders.map(&:cache_name).compact
60
+ end
61
+
62
+ def cache_names=(cache_names)
63
+ return if not cache_names or cache_names == "" or uploaders.any?(&:cached?)
64
+ @uploaders = cache_names.map do |cache_name|
65
+ uploader = blank_uploader
66
+ uploader.retrieve_from_cache!(cache_name)
67
+ uploader
68
+ end
69
+ rescue CarrierWave::InvalidParameter
70
+ end
71
+
72
+ def remote_urls=(urls)
73
+ return if not urls or urls == "" or urls.all?(&:blank?)
74
+
75
+ @remote_urls = urls
76
+ @download_error = nil
77
+ @integrity_error = nil
78
+
79
+ @uploaders = urls.zip(remote_request_headers || []).map do |url, header|
80
+ uploader = blank_uploader
81
+ uploader.download!(url, header || {})
82
+ uploader
83
+ end
84
+
85
+ rescue CarrierWave::DownloadError => e
86
+ @download_error = e
87
+ raise e unless option(:ignore_download_errors)
88
+ rescue CarrierWave::ProcessingError => e
89
+ @processing_error = e
90
+ raise e unless option(:ignore_processing_errors)
91
+ rescue CarrierWave::IntegrityError => e
92
+ @integrity_error = e
93
+ raise e unless option(:ignore_integrity_errors)
94
+ end
95
+
96
+ def store!
97
+ if remove?
98
+ remove!
99
+ else
100
+ uploaders.reject(&:blank?).each(&:store!)
101
+ end
102
+ end
103
+
104
+ def urls(*args)
105
+ uploaders.map { |u| u.url(*args) }
106
+ end
107
+
108
+ def blank?
109
+ uploaders.none?(&:present?)
110
+ end
111
+
112
+ def remove?
113
+ remove.present? && remove !~ /\A0|false$\z/
114
+ end
115
+
116
+ def remove!
117
+ uploaders.reject(&:blank?).each(&:remove!)
118
+ @uploaders = []
119
+ end
120
+
121
+ def serialization_column
122
+ option(:mount_on) || column
123
+ end
124
+
125
+ def remove_previous(before=nil, after=nil)
126
+ return unless before
127
+
128
+ # both 'before' and 'after' can be string when 'mount_on' option is set
129
+ before = before.reject(&:blank?).map do |value|
130
+ if value.is_a?(String)
131
+ uploader = blank_uploader
132
+ uploader.retrieve_from_store!(value)
133
+ uploader
134
+ else
135
+ value
136
+ end
137
+ end
138
+ after_paths = after.reject(&:blank?).map do |value|
139
+ if value.is_a?(String)
140
+ uploader = blank_uploader
141
+ uploader.retrieve_from_store!(value)
142
+ uploader
143
+ else
144
+ value
145
+ end.path
146
+ end
147
+ before.each do |uploader|
148
+ if uploader.remove_previously_stored_files_after_update and not after_paths.include?(uploader.path)
149
+ uploader.remove!
150
+ end
151
+ end
152
+ end
153
+
154
+ attr_accessor :uploader_options
155
+
156
+ private
157
+
158
+ def option(name)
159
+ self.uploader_options ||= {}
160
+ self.uploader_options[name] ||= record.class.uploader_option(column, name)
161
+ end
162
+
163
+ end # Mounter
164
+ end # CarrierWave