carrierwave 0.11.2 → 3.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +452 -178
  3. data/lib/carrierwave/compatibility/paperclip.rb +4 -4
  4. data/lib/carrierwave/downloader/base.rb +101 -0
  5. data/lib/carrierwave/downloader/remote_file.rb +68 -0
  6. data/lib/carrierwave/error.rb +1 -0
  7. data/lib/carrierwave/locale/en.yml +11 -5
  8. data/lib/carrierwave/mount.rb +217 -182
  9. data/lib/carrierwave/mounter.rb +255 -0
  10. data/lib/carrierwave/orm/activerecord.rb +29 -35
  11. data/lib/carrierwave/processing/mini_magick.rb +140 -84
  12. data/lib/carrierwave/processing/rmagick.rb +72 -21
  13. data/lib/carrierwave/processing/vips.rb +284 -0
  14. data/lib/carrierwave/processing.rb +1 -1
  15. data/lib/carrierwave/sanitized_file.rb +83 -84
  16. data/lib/carrierwave/storage/abstract.rb +16 -3
  17. data/lib/carrierwave/storage/file.rb +71 -3
  18. data/lib/carrierwave/storage/fog.rb +215 -57
  19. data/lib/carrierwave/storage.rb +1 -9
  20. data/lib/carrierwave/test/matchers.rb +88 -19
  21. data/lib/carrierwave/uploader/cache.rb +75 -45
  22. data/lib/carrierwave/uploader/callbacks.rb +1 -3
  23. data/lib/carrierwave/uploader/configuration.rb +80 -16
  24. data/lib/carrierwave/uploader/content_type_allowlist.rb +62 -0
  25. data/lib/carrierwave/uploader/content_type_denylist.rb +62 -0
  26. data/lib/carrierwave/uploader/default_url.rb +3 -5
  27. data/lib/carrierwave/uploader/dimension.rb +66 -0
  28. data/lib/carrierwave/uploader/download.rb +4 -74
  29. data/lib/carrierwave/uploader/extension_allowlist.rb +63 -0
  30. data/lib/carrierwave/uploader/extension_denylist.rb +64 -0
  31. data/lib/carrierwave/uploader/file_size.rb +43 -0
  32. data/lib/carrierwave/uploader/mountable.rb +13 -8
  33. data/lib/carrierwave/uploader/processing.rb +48 -13
  34. data/lib/carrierwave/uploader/proxy.rb +20 -9
  35. data/lib/carrierwave/uploader/remove.rb +0 -2
  36. data/lib/carrierwave/uploader/serialization.rb +2 -4
  37. data/lib/carrierwave/uploader/store.rb +59 -28
  38. data/lib/carrierwave/uploader/url.rb +8 -7
  39. data/lib/carrierwave/uploader/versions.rb +171 -123
  40. data/lib/carrierwave/uploader.rb +12 -10
  41. data/lib/carrierwave/utilities/file_name.rb +47 -0
  42. data/lib/carrierwave/utilities/uri.rb +14 -12
  43. data/lib/carrierwave/utilities.rb +1 -3
  44. data/lib/carrierwave/validations/active_model.rb +7 -11
  45. data/lib/carrierwave/version.rb +1 -1
  46. data/lib/carrierwave.rb +39 -21
  47. data/lib/generators/templates/{uploader.rb → uploader.rb.erb} +6 -10
  48. data/lib/generators/uploader_generator.rb +3 -3
  49. metadata +135 -83
  50. data/lib/carrierwave/locale/cs.yml +0 -11
  51. data/lib/carrierwave/locale/de.yml +0 -11
  52. data/lib/carrierwave/locale/el.yml +0 -11
  53. data/lib/carrierwave/locale/es.yml +0 -11
  54. data/lib/carrierwave/locale/fr.yml +0 -11
  55. data/lib/carrierwave/locale/ja.yml +0 -11
  56. data/lib/carrierwave/locale/nb.yml +0 -11
  57. data/lib/carrierwave/locale/nl.yml +0 -11
  58. data/lib/carrierwave/locale/pl.yml +0 -11
  59. data/lib/carrierwave/locale/pt-BR.yml +0 -11
  60. data/lib/carrierwave/locale/pt-PT.yml +0 -11
  61. data/lib/carrierwave/locale/ru.yml +0 -11
  62. data/lib/carrierwave/locale/sk.yml +0 -11
  63. data/lib/carrierwave/locale/tr.yml +0 -11
  64. data/lib/carrierwave/processing/mime_types.rb +0 -74
  65. data/lib/carrierwave/uploader/content_type_blacklist.rb +0 -48
  66. data/lib/carrierwave/uploader/content_type_whitelist.rb +0 -48
  67. data/lib/carrierwave/uploader/extension_blacklist.rb +0 -47
  68. data/lib/carrierwave/uploader/extension_whitelist.rb +0 -49
  69. data/lib/carrierwave/utilities/deprecation.rb +0 -18
@@ -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,218 @@ module CarrierWave
135
132
  # end
136
133
  #
137
134
  def mount_uploader(column, uploader=nil, options={}, &block)
138
- include CarrierWave::Mount::Extension
135
+ mount_base(column, uploader, options.merge(multiple: false), &block)
139
136
 
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
150
-
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 #{column}_identifier
174
+ _mounter(:#{column}).read_identifiers[0]
175
+ end
176
+
177
+ def #{column}_integrity_error
178
+ #{column}_integrity_errors.last
179
+ end
180
+
181
+ def #{column}_processing_error
182
+ #{column}_processing_errors.last
183
+ end
184
+
185
+ def #{column}_download_error
186
+ #{column}_download_errors.last
187
+ end
188
+ RUBY
189
+ end
190
+
191
+ ##
192
+ # Mounts the given uploader on the given array column. This means that
193
+ # assigning and reading from the array column will upload and retrieve
194
+ # multiple files. Supposing that a User class has an uploader mounted on
195
+ # images, and that images can store an array, for example it could be a
196
+ # PostgreSQL JSON column. You can assign and retrieve files like this:
197
+ #
198
+ # @user.images # => []
199
+ # @user.images = [some_file_object]
200
+ # @user.images # => [<Uploader>]
201
+ #
202
+ # @user.images[0].url # => '/some_url.png'
203
+ #
204
+ # It is also possible (but not recommended) to omit the uploader, which
205
+ # will create an anonymous uploader class.
206
+ #
207
+ # Passing a block makes it possible to customize the uploader. This can be
208
+ # convenient for brevity, but if there is any significant logic in the
209
+ # uploader, you should do the right thing and have it in its own file.
210
+ #
211
+ # === Added instance methods
212
+ #
213
+ # Supposing a class has used +mount_uploaders+ to mount an uploader on a column
214
+ # named +images+, in that case the following methods will be added to the class:
215
+ #
216
+ # [images] Returns an array of uploaders for each uploaded file
217
+ # [images=] Caches the given files
218
+ #
219
+ # [images_urls] Returns the urls to the uploaded files
220
+ #
221
+ # [images_cache] Returns a string that identifies the cache location of the files
222
+ # [images_cache=] Retrieves the files from the cache based on the given cache name
223
+ #
224
+ # [remote_image_urls] Returns previously cached remote urls
225
+ # [remote_image_urls=] Retrieve files from the given remote urls
226
+ #
227
+ # [remove_images] An attribute reader that can be used with a checkbox to mark the files for removal
228
+ # [remove_images=] An attribute writer that can be used with a checkbox to mark the files for removal
229
+ # [remove_images?] Whether the files should be removed when store_image! is called.
230
+ #
231
+ # [store_images!] Stores all files that have been assigned with +images=+
232
+ # [remove_images!] Removes the uploaded file from the filesystem.
233
+ #
234
+ # [image_integrity_errors] Returns error objects of files which failed to pass integrity check
235
+ # [image_processing_errors] Returns error objects of files which failed to be processed
236
+ # [image_download_errors] Returns error objects of files which failed to be downloaded
237
+ #
238
+ # [image_identifiers] Reads out the identifiers of the files
239
+ #
240
+ # === Parameters
241
+ #
242
+ # [column (Symbol)] the attribute to mount this uploader on
243
+ # [uploader (CarrierWave::Uploader)] the uploader class to mount
244
+ # [options (Hash{Symbol => Object})] a set of options
245
+ # [&block (Proc)] customize anonymous uploaders
246
+ #
247
+ # === Options
248
+ #
249
+ # [:mount_on => Symbol] if the name of the column to be serialized to differs you can override it using this option
250
+ # [:ignore_integrity_errors => Boolean] if set to true, integrity errors will result in caching failing silently
251
+ # [:ignore_processing_errors => Boolean] if set to true, processing errors will result in caching failing silently
252
+ #
253
+ # === Examples
254
+ #
255
+ # Mounting uploaders on different columns.
256
+ #
257
+ # class Song
258
+ # mount_uploaders :lyrics, LyricsUploader
259
+ # mount_uploaders :alternative_lyrics, LyricsUploader
260
+ # mount_uploaders :files, SongUploader
261
+ # end
262
+ #
263
+ # This will add an anonymous uploader with only the default settings:
264
+ #
265
+ # class Data
266
+ # mount_uploaders :csv_files
267
+ # end
268
+ #
269
+ # this will add an anonymous uploader overriding the store_dir:
270
+ #
271
+ # class Product
272
+ # mount_uploaders :blueprints do
273
+ # def store_dir
274
+ # 'blueprints'
275
+ # end
276
+ # end
277
+ # end
278
+ #
279
+ def mount_uploaders(column, uploader=nil, options={}, &block)
280
+ mount_base(column, uploader, options.merge(multiple: true), &block)
281
+
282
+ mod = Module.new
283
+ include mod
284
+ mod.class_eval <<-RUBY, __FILE__, __LINE__+1
285
+
286
+ def #{column}
287
+ _mounter(:#{column}).uploaders
288
+ end
289
+
290
+ def #{column}=(new_files)
291
+ _mounter(:#{column}).cache(new_files)
292
+ end
293
+
294
+ def #{column}_urls(*args)
295
+ _mounter(:#{column}).urls(*args)
296
+ end
297
+
298
+ def #{column}_cache
299
+ names = _mounter(:#{column}).cache_names
300
+ names.to_json if names.present?
301
+ end
302
+
303
+ def #{column}_cache=(cache_name)
304
+ _mounter(:#{column}).cache_names = JSON.parse(cache_name) if cache_name.present?
305
+ end
306
+
307
+ def remote_#{column}_urls
308
+ _mounter(:#{column}).remote_urls
309
+ end
310
+
311
+ def remote_#{column}_urls=(urls)
312
+ _mounter(:#{column}).remote_urls = urls
313
+ end
314
+
315
+ def remote_#{column}_request_headers=(headers)
316
+ _mounter(:#{column}).remote_request_headers = headers
317
+ end
318
+
319
+ def #{column}_identifiers
320
+ _mounter(:#{column}).read_identifiers
321
+ end
322
+ RUBY
323
+ end
324
+
325
+ private
326
+
327
+ def mount_base(column, uploader=nil, options={}, &block)
328
+ include CarrierWave::Mount::Extension
329
+
330
+ uploader = build_uploader(uploader, column, &block)
331
+ uploaders[column.to_sym] = uploader
332
+ uploader_options[column.to_sym] = options
333
+
334
+ # Make sure to write over accessors directly defined on the class.
335
+ # Simply super to the included module below.
336
+ class_eval <<-RUBY, __FILE__, __LINE__+1
337
+ def #{column}; super; end
338
+ def #{column}=(new_file); super; end
339
+ RUBY
340
+
341
+ mod = Module.new
342
+ include mod
343
+ mod.class_eval <<-RUBY, __FILE__, __LINE__+1
344
+
345
+ def #{column}?
346
+ _mounter(:#{column}).present?
188
347
  end
189
348
 
190
349
  def remove_#{column}
@@ -193,6 +352,8 @@ module CarrierWave
193
352
 
194
353
  def remove_#{column}!
195
354
  _mounter(:#{column}).remove!
355
+ self.remove_#{column} = true
356
+ write_#{column}_identifier
196
357
  end
197
358
 
198
359
  def remove_#{column}=(value)
@@ -207,64 +368,48 @@ module CarrierWave
207
368
  _mounter(:#{column}).store!
208
369
  end
209
370
 
210
- def #{column}_integrity_error
211
- _mounter(:#{column}).integrity_error
371
+ def #{column}_integrity_errors
372
+ _mounter(:#{column}).integrity_errors
212
373
  end
213
374
 
214
- def #{column}_processing_error
215
- _mounter(:#{column}).processing_error
375
+ def #{column}_processing_errors
376
+ _mounter(:#{column}).processing_errors
216
377
  end
217
378
 
218
- def #{column}_download_error
219
- _mounter(:#{column}).download_error
379
+ def #{column}_download_errors
380
+ _mounter(:#{column}).download_errors
220
381
  end
221
382
 
222
383
  def write_#{column}_identifier
223
384
  _mounter(:#{column}).write_identifier
224
385
  end
225
386
 
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
387
+ def mark_remove_#{column}_false
388
+ _mounter(:#{column}).remove = false
236
389
  end
237
390
 
238
- def find_previous_model_for_#{column}
239
- self.class.find(to_key.first)
391
+ def reset_previous_changes_for_#{column}
392
+ _mounter(:#{column}).reset_changes!
240
393
  end
241
394
 
242
395
  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
396
+ _mounter(:#{column}).remove_previous
247
397
  end
248
398
 
249
- def mark_remove_#{column}_false
250
- _mounter(:#{column}).remove = false
399
+ def remove_rolled_back_#{column}
400
+ _mounter(:#{column}).remove_added
251
401
  end
252
-
253
402
  RUBY
254
403
  end
255
404
 
256
- private
257
-
258
- def build_uploader(uploader, &block)
259
- return uploader if uploader && !block_given?
405
+ def build_uploader(uploader, column, &block)
406
+ uploader ||= CarrierWave::Uploader::Base
407
+ return uploader unless block_given?
260
408
 
261
- uploader = Class.new(uploader || CarrierWave::Uploader::Base)
262
- const_set("Uploader#{uploader.object_id}".gsub('-', '_'), uploader)
409
+ uploader = Class.new(uploader)
410
+ const_set("CarrierWave#{column.to_s.camelize}Uploader", uploader)
263
411
 
264
- if block_given?
265
- uploader.class_eval(&block)
266
- uploader.recursively_apply_block_to_versions(&block)
267
- end
412
+ uploader.class_eval(&block)
268
413
 
269
414
  uploader
270
415
  end
@@ -283,129 +428,19 @@ module CarrierWave
283
428
 
284
429
  private
285
430
 
431
+ def initialize_dup(other)
432
+ @_mounters = @_mounters.dup
433
+ super
434
+ end
435
+
286
436
  def _mounter(column)
287
437
  # We cannot memoize in frozen objects :(
288
- return Mounter.new(self, column) if frozen?
438
+ return Mounter.build(self, column) if frozen?
289
439
  @_mounters ||= {}
290
- @_mounters[column] ||= Mounter.new(self, column)
440
+ @_mounters[column] ||= Mounter.build(self, column)
291
441
  end
292
442
 
293
443
  end # Extension
294
444
 
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
445
  end # Mount
411
446
  end # CarrierWave