carrierwave 0.11.2 → 1.0.0.beta

Sign up to get free protection for your applications and to get access to all the features.

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 +220 -116
  3. data/lib/carrierwave.rb +8 -10
  4. data/lib/carrierwave/compatibility/paperclip.rb +0 -2
  5. data/lib/carrierwave/error.rb +1 -0
  6. data/lib/carrierwave/locale/en.yml +7 -4
  7. data/lib/carrierwave/mount.rb +209 -176
  8. data/lib/carrierwave/mounter.rb +163 -0
  9. data/lib/carrierwave/orm/activerecord.rb +49 -20
  10. data/lib/carrierwave/processing.rb +0 -1
  11. data/lib/carrierwave/processing/mini_magick.rb +64 -13
  12. data/lib/carrierwave/processing/rmagick.rb +31 -3
  13. data/lib/carrierwave/sanitized_file.rb +43 -38
  14. data/lib/carrierwave/storage.rb +0 -9
  15. data/lib/carrierwave/storage/abstract.rb +15 -2
  16. data/lib/carrierwave/storage/file.rb +64 -2
  17. data/lib/carrierwave/storage/fog.rb +100 -27
  18. data/lib/carrierwave/test/matchers.rb +77 -12
  19. data/lib/carrierwave/uploader.rb +2 -2
  20. data/lib/carrierwave/uploader/cache.rb +40 -26
  21. data/lib/carrierwave/uploader/callbacks.rb +0 -2
  22. data/lib/carrierwave/uploader/configuration.rb +48 -6
  23. data/lib/carrierwave/uploader/default_url.rb +3 -5
  24. data/lib/carrierwave/uploader/download.rb +2 -4
  25. data/lib/carrierwave/uploader/extension_blacklist.rb +14 -10
  26. data/lib/carrierwave/uploader/extension_whitelist.rb +12 -10
  27. data/lib/carrierwave/uploader/file_size.rb +41 -0
  28. data/lib/carrierwave/uploader/magic_mime_blacklist.rb +94 -0
  29. data/lib/carrierwave/uploader/magic_mime_whitelist.rb +94 -0
  30. data/lib/carrierwave/uploader/mountable.rb +7 -8
  31. data/lib/carrierwave/uploader/processing.rb +1 -3
  32. data/lib/carrierwave/uploader/proxy.rb +5 -7
  33. data/lib/carrierwave/uploader/remove.rb +0 -2
  34. data/lib/carrierwave/uploader/serialization.rb +1 -3
  35. data/lib/carrierwave/uploader/store.rb +5 -23
  36. data/lib/carrierwave/uploader/url.rb +1 -3
  37. data/lib/carrierwave/uploader/versions.rb +75 -82
  38. data/lib/carrierwave/utilities.rb +0 -3
  39. data/lib/carrierwave/utilities/uri.rb +4 -7
  40. data/lib/carrierwave/validations/active_model.rb +0 -2
  41. data/lib/carrierwave/version.rb +1 -1
  42. data/lib/generators/templates/uploader.rb +3 -5
  43. metadata +43 -97
  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
@@ -1,7 +1,6 @@
1
- # encoding: utf-8
2
-
3
1
  require 'fileutils'
4
2
  require 'active_support/core_ext/object/blank'
3
+ require 'active_support/core_ext/object/try'
5
4
  require 'active_support/core_ext/class/attribute'
6
5
  require 'active_support/concern'
7
6
 
@@ -9,6 +8,7 @@ module CarrierWave
9
8
 
10
9
  class << self
11
10
  attr_accessor :root, :base_path
11
+ attr_writer :tmp_path
12
12
 
13
13
  def configure(&block)
14
14
  CarrierWave::Uploader::Base.configure(&block)
@@ -17,6 +17,10 @@ module CarrierWave
17
17
  def clean_cached_files!(seconds=60*60*24)
18
18
  CarrierWave::Uploader::Base.clean_cached_files!(seconds)
19
19
  end
20
+
21
+ def tmp_path
22
+ @tmp_path ||= File.expand_path(File.join('..', 'tmp'), root)
23
+ end
20
24
  end
21
25
 
22
26
  end
@@ -34,7 +38,7 @@ elsif defined?(Rails)
34
38
 
35
39
  module CarrierWave
36
40
  class Railtie < Rails::Railtie
37
- initializer "carrierwave.setup_paths" do
41
+ initializer "carrierwave.setup_paths" do |app|
38
42
  CarrierWave.root = Rails.root.join(Rails.public_path).to_s
39
43
  CarrierWave.base_path = ENV['RAILS_RELATIVE_URL_ROOT']
40
44
  end
@@ -44,13 +48,6 @@ elsif defined?(Rails)
44
48
  require 'carrierwave/orm/activerecord'
45
49
  end
46
50
  end
47
-
48
- ##
49
- # Loads the Carrierwave locale files before the Rails application locales
50
- # letting the Rails application overrite the carrierwave locale defaults
51
- config.before_configuration do
52
- I18n.load_path << File.join(File.dirname(__FILE__), "carrierwave", "locale", 'en.yml')
53
- end
54
51
  end
55
52
  end
56
53
 
@@ -72,6 +69,7 @@ end
72
69
  require "carrierwave/utilities"
73
70
  require "carrierwave/error"
74
71
  require "carrierwave/sanitized_file"
72
+ require "carrierwave/mounter"
75
73
  require "carrierwave/mount"
76
74
  require "carrierwave/processing"
77
75
  require "carrierwave/version"
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
-
3
1
  module CarrierWave
4
2
  module Compatibility
5
3
 
@@ -4,4 +4,5 @@ module CarrierWave
4
4
  class InvalidParameter < UploadError; end
5
5
  class ProcessingError < UploadError; end
6
6
  class DownloadError < UploadError; end
7
+ class UnknownStorageError < StandardError; end
7
8
  end
@@ -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,237 @@ 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 write_#{column}_identifier
170
+ return if frozen?
171
+ mounter = _mounter(:#{column})
172
+
173
+ if mounter.remove?
174
+ write_uploader(mounter.serialization_column, nil)
175
+ elsif mounter.identifiers.first
176
+ write_uploader(mounter.serialization_column, mounter.identifiers.first)
177
+ end
178
+ end
179
+
180
+ def #{column}_identifier
181
+ _mounter(:#{column}).read_identifiers[0]
182
+ end
183
+
184
+ def store_previous_changes_for_#{column}
185
+ @_previous_changes_for_#{column} = changes[_mounter(:#{column}).serialization_column]
186
+ end
187
+
188
+ def remove_previously_stored_#{column}
189
+ before, after = @_previous_changes_for_#{column}
190
+ _mounter(:#{column}).remove_previous([before], [after])
191
+ end
192
+ RUBY
193
+ end
194
+
195
+ ##
196
+ # Mounts the given uploader on the given array column. This means that
197
+ # assigning and reading from the array column will upload and retrieve
198
+ # multiple files. Supposing that a User class has an uploader mounted on
199
+ # images, and that images can store an array, for example it could be a
200
+ # PostgreSQL JSON column. You can assign and retrieve files like this:
201
+ #
202
+ # @user.images # => []
203
+ # @user.images = [some_file_object]
204
+ # @user.images # => [<Uploader>]
205
+ #
206
+ # @user.images[0].url # => '/some_url.png'
207
+ #
208
+ # It is also possible (but not recommended) to omit the uploader, which
209
+ # will create an anonymous uploader class.
210
+ #
211
+ # Passing a block makes it possible to customize the uploader. This can be
212
+ # convenient for brevity, but if there is any significant logic in the
213
+ # uploader, you should do the right thing and have it in its own file.
214
+ #
215
+ # === Added instance methods
216
+ #
217
+ # Supposing a class has used +mount_uploaders+ to mount an uploader on a column
218
+ # named +images+, in that case the following methods will be added to the class:
219
+ #
220
+ # [images] Returns an array of uploaders for each uploaded file
221
+ # [images=] Caches the given files
222
+ #
223
+ # [images_urls] Returns the urls to the uploaded files
224
+ #
225
+ # [images_cache] Returns a string that identifies the cache location of the files
226
+ # [images_cache=] Retrieves the files from the cache based on the given cache name
227
+ #
228
+ # [remote_image_urls] Returns previously cached remote urls
229
+ # [remote_image_urls=] Retrieve files from the given remote urls
230
+ #
231
+ # [remove_images] An attribute reader that can be used with a checkbox to mark the files for removal
232
+ # [remove_images=] An attribute writer that can be used with a checkbox to mark the files for removal
233
+ # [remove_images?] Whether the files should be removed when store_image! is called.
234
+ #
235
+ # [store_images!] Stores all files that have been assigned with +images=+
236
+ # [remove_images!] Removes the uploaded file from the filesystem.
237
+ #
238
+ # [images_integrity_error] Returns an error object if the last files to be assigned caused an integrity error
239
+ # [images_processing_error] Returns an error object if the last files to be assigned caused a processing error
240
+ # [images_download_error] Returns an error object if the last files to be remotely assigned caused a download error
241
+ #
242
+ # [image_identifiers] Reads out the identifiers of the files
243
+ #
244
+ # === Parameters
245
+ #
246
+ # [column (Symbol)] the attribute to mount this uploader on
247
+ # [uploader (CarrierWave::Uploader)] the uploader class to mount
248
+ # [options (Hash{Symbol => Object})] a set of options
249
+ # [&block (Proc)] customize anonymous uploaders
250
+ #
251
+ # === Options
252
+ #
253
+ # [:mount_on => Symbol] if the name of the column to be serialized to differs you can override it using this option
254
+ # [:ignore_integrity_errors => Boolean] if set to true, integrity errors will result in caching failing silently
255
+ # [:ignore_processing_errors => Boolean] if set to true, processing errors will result in caching failing silently
256
+ #
257
+ # === Examples
258
+ #
259
+ # Mounting uploaders on different columns.
260
+ #
261
+ # class Song
262
+ # mount_uploaders :lyrics, LyricsUploader
263
+ # mount_uploaders :alternative_lyrics, LyricsUploader
264
+ # mount_uploaders :files, SongUploader
265
+ # end
266
+ #
267
+ # This will add an anonymous uploader with only the default settings:
268
+ #
269
+ # class Data
270
+ # mount_uploaders :csv_files
271
+ # end
272
+ #
273
+ # this will add an anonymous uploader overriding the store_dir:
274
+ #
275
+ # class Product
276
+ # mount_uploaders :blueprints do
277
+ # def store_dir
278
+ # 'blueprints'
279
+ # end
280
+ # end
281
+ # end
282
+ #
283
+ def mount_uploaders(column, uploader=nil, options={}, &block)
284
+ mount_base(column, uploader, options, &block)
285
+
286
+ mod = Module.new
287
+ include mod
288
+ mod.class_eval <<-RUBY, __FILE__, __LINE__+1
289
+
290
+ def #{column}
291
+ _mounter(:#{column}).uploaders
292
+ end
293
+
294
+ def #{column}=(new_files)
295
+ _mounter(:#{column}).cache(new_files)
296
+ end
297
+
298
+ def #{column}_urls(*args)
299
+ _mounter(:#{column}).urls(*args)
300
+ end
301
+
302
+ def #{column}_cache
303
+ names = _mounter(:#{column}).cache_names
304
+ names.to_json if names.present?
305
+ end
306
+
307
+ def #{column}_cache=(cache_name)
308
+ _mounter(:#{column}).cache_names = JSON.parse(cache_name) if cache_name.present?
309
+ end
310
+
311
+ def remote_#{column}_urls
312
+ _mounter(:#{column}).remote_urls
313
+ end
314
+
315
+ def remote_#{column}_urls=(urls)
316
+ _mounter(:#{column}).remote_urls = urls
317
+ end
318
+
319
+ def write_#{column}_identifier
320
+ return if frozen?
321
+ mounter = _mounter(:#{column})
322
+
323
+ if mounter.remove?
324
+ write_uploader(mounter.serialization_column, nil)
325
+ elsif mounter.identifiers.any?
326
+ write_uploader(mounter.serialization_column, mounter.identifiers)
327
+ end
328
+ end
329
+
330
+ def #{column}_identifiers
331
+ _mounter(:#{column}).read_identifiers
332
+ end
333
+
334
+ def store_previous_changes_for_#{column}
335
+ @_previous_changes_for_#{column} = changes[_mounter(:#{column}).serialization_column]
336
+ end
337
+
338
+ def remove_previously_stored_#{column}
339
+ _mounter(:#{column}).remove_previous(*@_previous_changes_for_#{column})
340
+ end
341
+ RUBY
342
+ end
343
+
344
+ private
345
+
346
+ def mount_base(column, uploader=nil, options={}, &block)
347
+ include CarrierWave::Mount::Extension
348
+
349
+ uploader = build_uploader(uploader, &block)
350
+ uploaders[column.to_sym] = uploader
351
+ uploader_options[column.to_sym] = options
352
+
353
+ # Make sure to write over accessors directly defined on the class.
354
+ # Simply super to the included module below.
355
+ class_eval <<-RUBY, __FILE__, __LINE__+1
356
+ def #{column}; super; end
357
+ def #{column}=(new_file); super; end
358
+ RUBY
359
+
360
+ mod = Module.new
361
+ include mod
362
+ mod.class_eval <<-RUBY, __FILE__, __LINE__+1
363
+
364
+ def #{column}?
365
+ _mounter(:#{column}).present?
188
366
  end
189
367
 
190
368
  def remove_#{column}
@@ -219,47 +397,17 @@ module CarrierWave
219
397
  _mounter(:#{column}).download_error
220
398
  end
221
399
 
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
400
  def mark_remove_#{column}_false
250
401
  _mounter(:#{column}).remove = false
251
402
  end
252
-
253
403
  RUBY
254
404
  end
255
405
 
256
- private
257
-
258
406
  def build_uploader(uploader, &block)
259
407
  return uploader if uploader && !block_given?
260
408
 
261
409
  uploader = Class.new(uploader || CarrierWave::Uploader::Base)
262
- const_set("Uploader#{uploader.object_id}".gsub('-', '_'), uploader)
410
+ const_set("Uploader#{uploader.object_id}".tr('-', '_'), uploader)
263
411
 
264
412
  if block_given?
265
413
  uploader.class_eval(&block)
@@ -292,120 +440,5 @@ module CarrierWave
292
440
 
293
441
  end # Extension
294
442
 
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
443
  end # Mount
411
444
  end # CarrierWave