carrierwave 2.2.6 → 3.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +137 -67
  3. data/lib/carrierwave/compatibility/paperclip.rb +4 -2
  4. data/lib/carrierwave/downloader/base.rb +19 -11
  5. data/lib/carrierwave/downloader/remote_file.rb +13 -10
  6. data/lib/carrierwave/locale/en.yml +5 -3
  7. data/lib/carrierwave/mount.rb +36 -50
  8. data/lib/carrierwave/mounter.rb +117 -50
  9. data/lib/carrierwave/orm/activerecord.rb +21 -62
  10. data/lib/carrierwave/processing/mini_magick.rb +15 -13
  11. data/lib/carrierwave/processing/rmagick.rb +11 -15
  12. data/lib/carrierwave/processing/vips.rb +12 -12
  13. data/lib/carrierwave/sanitized_file.rb +49 -77
  14. data/lib/carrierwave/storage/abstract.rb +5 -5
  15. data/lib/carrierwave/storage/file.rb +6 -5
  16. data/lib/carrierwave/storage/fog.rb +74 -66
  17. data/lib/carrierwave/test/matchers.rb +11 -7
  18. data/lib/carrierwave/uploader/cache.rb +18 -10
  19. data/lib/carrierwave/uploader/callbacks.rb +1 -1
  20. data/lib/carrierwave/uploader/configuration.rb +10 -4
  21. data/lib/carrierwave/uploader/{content_type_whitelist.rb → content_type_allowlist.rb} +17 -15
  22. data/lib/carrierwave/uploader/{content_type_blacklist.rb → content_type_denylist.rb} +19 -14
  23. data/lib/carrierwave/uploader/dimension.rb +66 -0
  24. data/lib/carrierwave/uploader/{extension_whitelist.rb → extension_allowlist.rb} +17 -15
  25. data/lib/carrierwave/uploader/{extension_blacklist.rb → extension_denylist.rb} +18 -13
  26. data/lib/carrierwave/uploader/file_size.rb +2 -2
  27. data/lib/carrierwave/uploader/processing.rb +31 -6
  28. data/lib/carrierwave/uploader/proxy.rb +16 -3
  29. data/lib/carrierwave/uploader/store.rb +44 -6
  30. data/lib/carrierwave/uploader/url.rb +1 -1
  31. data/lib/carrierwave/uploader/versions.rb +154 -136
  32. data/lib/carrierwave/uploader.rb +10 -8
  33. data/lib/carrierwave/utilities/file_name.rb +47 -0
  34. data/lib/carrierwave/utilities/uri.rb +14 -11
  35. data/lib/carrierwave/utilities.rb +1 -0
  36. data/lib/carrierwave/validations/active_model.rb +4 -6
  37. data/lib/carrierwave/version.rb +1 -1
  38. data/lib/carrierwave.rb +9 -17
  39. data/lib/generators/templates/{uploader.rb → uploader.rb.erb} +1 -1
  40. data/lib/generators/uploader_generator.rb +3 -3
  41. metadata +32 -44
@@ -24,7 +24,8 @@ module CarrierWave
24
24
  # [String] a cache id in the format TIMEINT-PID-COUNTER-RND
25
25
  #
26
26
  def self.generate_cache_id
27
- [Time.now.utc.to_i,
27
+ [
28
+ Time.now.utc.to_i,
28
29
  SecureRandom.random_number(1_000_000_000_000_000),
29
30
  '%04d' % (CarrierWave::CacheCounter.increment % 10_000),
30
31
  '%04d' % SecureRandom.random_number(10_000)
@@ -64,7 +65,7 @@ module CarrierWave
64
65
  # It's recommended that you keep cache files in one place only.
65
66
  #
66
67
  def clean_cached_files!(seconds=60*60*24)
67
- (cache_storage || storage).new(CarrierWave::Uploader::Base.new).clean_cache!(seconds)
68
+ (cache_storage || storage).new(new).clean_cache!(seconds)
68
69
  end
69
70
  end
70
71
 
@@ -102,7 +103,7 @@ module CarrierWave
102
103
  # [String] a cache name, in the format TIMEINT-PID-COUNTER-RND/filename.txt
103
104
  #
104
105
  def cache_name
105
- File.join(cache_id, full_original_filename) if cache_id && original_filename
106
+ File.join(cache_id, original_filename) if cache_id && original_filename
106
107
  end
107
108
 
108
109
  ##
@@ -110,7 +111,7 @@ module CarrierWave
110
111
  #
111
112
  # By default, cache!() uses copy_to(), which operates by copying the file
112
113
  # to the cache, then deleting the original file. If move_to_cache() is
113
- # overriden to return true, then cache!() uses move_to(), which simply
114
+ # overridden to return true, then cache!() uses move_to(), which simply
114
115
  # moves the file to the cache. Useful for large files.
115
116
  #
116
117
  # === Parameters
@@ -129,6 +130,7 @@ module CarrierWave
129
130
 
130
131
  self.cache_id = CarrierWave.generate_cache_id unless cache_id
131
132
 
133
+ @identifier = nil
132
134
  @staged = true
133
135
  @filename = new_file.filename
134
136
  self.original_filename = new_file.filename
@@ -165,7 +167,7 @@ module CarrierWave
165
167
  self.cache_id, self.original_filename = cache_name.to_s.split('/', 2)
166
168
  @staged = true
167
169
  @filename = original_filename
168
- @file = cache_storage.retrieve_from_cache!(full_filename(original_filename))
170
+ @file = cache_storage.retrieve_from_cache!(full_original_filename)
169
171
  end
170
172
  end
171
173
 
@@ -180,20 +182,21 @@ module CarrierWave
180
182
  #
181
183
  # [String] the cache path
182
184
  #
183
- def cache_path(for_file=full_filename(original_filename))
185
+ def cache_path(for_file=full_original_filename)
184
186
  File.join(*[cache_dir, @cache_id, for_file].compact)
185
187
  end
186
188
 
189
+ protected
190
+
191
+ attr_reader :cache_id
192
+
187
193
  private
188
194
 
189
195
  def workfile_path(for_file=original_filename)
190
196
  File.join(CarrierWave.tmp_path, @cache_id, version_name.to_s, for_file)
191
197
  end
192
198
 
193
- attr_reader :cache_id, :original_filename
194
-
195
- # We can override the full_original_filename method in other modules
196
- alias_method :full_original_filename, :original_filename
199
+ attr_reader :original_filename
197
200
 
198
201
  def cache_id=(cache_id)
199
202
  # Earlier version used 3 part cache_id. Thus we should allow for
@@ -210,6 +213,11 @@ module CarrierWave
210
213
  def cache_storage
211
214
  @cache_storage ||= (self.class.cache_storage || self.class.storage).new(self)
212
215
  end
216
+
217
+ # We can override the full_original_filename method in other modules
218
+ def full_original_filename
219
+ forcing_extension(original_filename)
220
+ end
213
221
  end # Cache
214
222
  end # Uploader
215
223
  end # CarrierWave
@@ -5,7 +5,7 @@ module CarrierWave
5
5
 
6
6
  included do
7
7
  class_attribute :_before_callbacks, :_after_callbacks,
8
- :instance_writer => false
8
+ :instance_writer => false
9
9
  self._before_callbacks = Hash.new []
10
10
  self._after_callbacks = Hash.new []
11
11
  end
@@ -24,6 +24,7 @@ module CarrierWave
24
24
  add_config :move_to_store
25
25
  add_config :remove_previously_stored_files_after_update
26
26
  add_config :downloader
27
+ add_config :force_extension
27
28
 
28
29
  # fog
29
30
  add_deprecated_config :fog_provider
@@ -44,6 +45,8 @@ module CarrierWave
44
45
  add_config :validate_download
45
46
  add_config :mount_on
46
47
  add_config :cache_only
48
+ add_config :download_retry_count
49
+ add_config :download_retry_wait_time
47
50
 
48
51
  # set default values
49
52
  reset_config
@@ -77,7 +80,7 @@ module CarrierWave
77
80
  def storage(storage = nil)
78
81
  case storage
79
82
  when Symbol
80
- if storage_engine = storage_engines[storage]
83
+ if (storage_engine = storage_engines[storage])
81
84
  self._storage = eval storage_engine
82
85
  else
83
86
  raise CarrierWave::UnknownStorageError, "Unknown storage: #{storage}"
@@ -123,7 +126,7 @@ module CarrierWave
123
126
  @#{name} = nil
124
127
 
125
128
  def self.#{name}(value=nil)
126
- @#{name} = value if value
129
+ @#{name} = value unless value.nil?
127
130
  return @#{name} if self.object_id == #{self.object_id} || defined?(@#{name})
128
131
  name = superclass.#{name}
129
132
  return nil if name.nil? && !instance_variable_defined?(:@#{name})
@@ -179,8 +182,8 @@ module CarrierWave
179
182
  #
180
183
  def reset_config
181
184
  configure do |config|
182
- config.permissions = 0644
183
- config.directory_permissions = 0755
185
+ config.permissions = 0o644
186
+ config.directory_permissions = 0o755
184
187
  config.storage_engines = {
185
188
  :file => "CarrierWave::Storage::File",
186
189
  :fog => "CarrierWave::Storage::Fog"
@@ -200,6 +203,7 @@ module CarrierWave
200
203
  config.move_to_store = false
201
204
  config.remove_previously_stored_files_after_update = true
202
205
  config.downloader = CarrierWave::Downloader::Base
206
+ config.force_extension = false
203
207
  config.ignore_integrity_errors = true
204
208
  config.ignore_processing_errors = true
205
209
  config.ignore_download_errors = true
@@ -210,6 +214,8 @@ module CarrierWave
210
214
  config.base_path = CarrierWave.base_path
211
215
  config.enable_processing = true
212
216
  config.ensure_multipart_form = true
217
+ config.download_retry_count = 0
218
+ config.download_retry_wait_time = 5
213
219
  end
214
220
  end
215
221
  end
@@ -1,10 +1,10 @@
1
1
  module CarrierWave
2
2
  module Uploader
3
- module ContentTypeWhitelist
3
+ module ContentTypeAllowlist
4
4
  extend ActiveSupport::Concern
5
5
 
6
6
  included do
7
- before :cache, :check_content_type_whitelist!
7
+ before :cache, :check_content_type_allowlist!
8
8
  end
9
9
 
10
10
  ##
@@ -29,32 +29,34 @@ module CarrierWave
29
29
  # end
30
30
  #
31
31
  def content_type_allowlist
32
- if respond_to?(:content_type_whitelist)
33
- ActiveSupport::Deprecation.warn "#content_type_whitelist is deprecated, use #content_type_allowlist instead." unless instance_variable_defined?(:@content_type_whitelist_warned)
34
- @content_type_whitelist_warned = true
35
- content_type_whitelist
36
- end
37
32
  end
38
33
 
39
34
  private
40
35
 
41
- def check_content_type_whitelist!(new_file)
42
- return unless content_type_allowlist
36
+ def check_content_type_allowlist!(new_file)
37
+ allowlist = content_type_allowlist
38
+ if !allowlist && respond_to?(:content_type_whitelist) && content_type_whitelist
39
+ ActiveSupport::Deprecation.warn "#content_type_whitelist is deprecated, use #content_type_allowlist instead." unless instance_variable_defined?(:@content_type_whitelist_warned)
40
+ @content_type_whitelist_warned = true
41
+ allowlist = content_type_whitelist
42
+ end
43
+
44
+ return unless allowlist
43
45
 
44
46
  content_type = new_file.content_type
45
- if !whitelisted_content_type?(content_type)
46
- raise CarrierWave::IntegrityError, I18n.translate(:"errors.messages.content_type_whitelist_error", content_type: content_type,
47
- allowed_types: Array(content_type_allowlist).join(", "), default: :"errors.messages.content_type_allowlist_error")
47
+ if !allowlisted_content_type?(allowlist, content_type)
48
+ raise CarrierWave::IntegrityError, I18n.translate(:"errors.messages.content_type_allowlist_error", content_type: content_type,
49
+ allowed_types: Array(allowlist).join(", "), default: :"errors.messages.content_type_whitelist_error")
48
50
  end
49
51
  end
50
52
 
51
- def whitelisted_content_type?(content_type)
52
- Array(content_type_allowlist).any? do |item|
53
+ def allowlisted_content_type?(allowlist, content_type)
54
+ Array(allowlist).any? do |item|
53
55
  item = Regexp.quote(item) if item.class != Regexp
54
56
  content_type =~ /\A#{item}/
55
57
  end
56
58
  end
57
59
 
58
- end # ContentTypeWhitelist
60
+ end # ContentTypeAllowlist
59
61
  end # Uploader
60
62
  end # CarrierWave
@@ -1,10 +1,10 @@
1
1
  module CarrierWave
2
2
  module Uploader
3
- module ContentTypeBlacklist
3
+ module ContentTypeDenylist
4
4
  extend ActiveSupport::Concern
5
5
 
6
6
  included do
7
- before :cache, :check_content_type_blacklist!
7
+ before :cache, :check_content_type_denylist!
8
8
  end
9
9
 
10
10
  ##
@@ -29,29 +29,34 @@ module CarrierWave
29
29
  # end
30
30
  #
31
31
  def content_type_denylist
32
- if respond_to?(:content_type_blacklist)
32
+ end
33
+
34
+ private
35
+
36
+ def check_content_type_denylist!(new_file)
37
+ denylist = content_type_denylist
38
+ if !denylist && respond_to?(:content_type_blacklist) && content_type_blacklist
33
39
  ActiveSupport::Deprecation.warn "#content_type_blacklist is deprecated, use #content_type_denylist instead." unless instance_variable_defined?(:@content_type_blacklist_warned)
34
40
  @content_type_blacklist_warned = true
35
- content_type_blacklist
41
+ denylist = content_type_blacklist
36
42
  end
37
- end
38
43
 
39
- private
44
+ return unless denylist
40
45
 
41
- def check_content_type_blacklist!(new_file)
42
- return unless content_type_denylist
46
+ ActiveSupport::Deprecation.warn "Use of #content_type_denylist is deprecated for the security reason, use #content_type_allowlist instead to explicitly state what are safe to accept" unless instance_variable_defined?(:@content_type_denylist_warned)
47
+ @content_type_denylist_warned = true
43
48
 
44
49
  content_type = new_file.content_type
45
- if blacklisted_content_type?(content_type)
46
- raise CarrierWave::IntegrityError, I18n.translate(:"errors.messages.content_type_blacklist_error",
47
- content_type: content_type, default: :"errors.messages.content_type_denylist_error")
50
+ if denylisted_content_type?(denylist, content_type)
51
+ raise CarrierWave::IntegrityError, I18n.translate(:"errors.messages.content_type_denylist_error",
52
+ content_type: content_type, default: :"errors.messages.content_type_blacklist_error")
48
53
  end
49
54
  end
50
55
 
51
- def blacklisted_content_type?(content_type)
52
- Array(content_type_denylist).any? { |item| content_type =~ /#{item}/ }
56
+ def denylisted_content_type?(denylist, content_type)
57
+ Array(denylist).any? { |item| content_type =~ /#{item}/ }
53
58
  end
54
59
 
55
- end # ContentTypeBlacklist
60
+ end # ContentTypeDenylist
56
61
  end # Uploader
57
62
  end # CarrierWave
@@ -0,0 +1,66 @@
1
+ require 'active_support'
2
+
3
+ module CarrierWave
4
+ module Uploader
5
+ module Dimension
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ before :cache, :check_dimensions!
10
+ end
11
+
12
+ ##
13
+ # Override this method in your uploader to provide a Range of width which
14
+ # are allowed to be uploaded.
15
+ # === Returns
16
+ #
17
+ # [NilClass, Range] a width range which are permitted to be uploaded
18
+ #
19
+ # === Examples
20
+ #
21
+ # def width_range
22
+ # 1000..2000
23
+ # end
24
+ #
25
+ def width_range; end
26
+
27
+ ##
28
+ # Override this method in your uploader to provide a Range of height which
29
+ # are allowed to be uploaded.
30
+ # === Returns
31
+ #
32
+ # [NilClass, Range] a height range which are permitted to be uploaded
33
+ #
34
+ # === Examples
35
+ #
36
+ # def height_range
37
+ # 1000..
38
+ # end
39
+ #
40
+ def height_range; end
41
+
42
+ private
43
+
44
+ def check_dimensions!(new_file)
45
+ # NOTE: Skip the check for resized images
46
+ return if version_name.present?
47
+ return unless width_range || height_range
48
+
49
+ unless respond_to?(:width) || respond_to?(:height)
50
+ raise 'You need to include one of CarrierWave::MiniMagick, CarrierWave::RMagick, or CarrierWave::Vips to perform image dimension validation'
51
+ end
52
+
53
+ if width_range&.begin && width < width_range.begin
54
+ raise CarrierWave::IntegrityError, I18n.translate(:"errors.messages.min_width_error", :min_width => ActiveSupport::NumberHelper.number_to_delimited(width_range.begin))
55
+ elsif width_range&.end && width > width_range.end
56
+ raise CarrierWave::IntegrityError, I18n.translate(:"errors.messages.max_width_error", :max_width => ActiveSupport::NumberHelper.number_to_delimited(width_range.end))
57
+ elsif height_range&.begin && height < height_range.begin
58
+ raise CarrierWave::IntegrityError, I18n.translate(:"errors.messages.min_height_error", :min_height => ActiveSupport::NumberHelper.number_to_delimited(height_range.begin))
59
+ elsif height_range&.end && height > height_range.end
60
+ raise CarrierWave::IntegrityError, I18n.translate(:"errors.messages.max_height_error", :max_height => ActiveSupport::NumberHelper.number_to_delimited(height_range.end))
61
+ end
62
+ end
63
+
64
+ end # Dimension
65
+ end # Uploader
66
+ end # CarrierWave
@@ -1,10 +1,10 @@
1
1
  module CarrierWave
2
2
  module Uploader
3
- module ExtensionWhitelist
3
+ module ExtensionAllowlist
4
4
  extend ActiveSupport::Concern
5
5
 
6
6
  included do
7
- before :cache, :check_extension_whitelist!
7
+ before :cache, :check_extension_allowlist!
8
8
  end
9
9
 
10
10
  ##
@@ -32,30 +32,32 @@ module CarrierWave
32
32
  # end
33
33
  #
34
34
  def extension_allowlist
35
- if respond_to?(:extension_whitelist)
36
- ActiveSupport::Deprecation.warn "#extension_whitelist is deprecated, use #extension_allowlist instead." unless instance_variable_defined?(:@extension_whitelist_warned)
37
- @extension_whitelist_warned = true
38
- extension_whitelist
39
- end
40
35
  end
41
36
 
42
37
  private
43
38
 
44
- def check_extension_whitelist!(new_file)
45
- return unless extension_allowlist
39
+ def check_extension_allowlist!(new_file)
40
+ allowlist = extension_allowlist
41
+ if !allowlist && respond_to?(:extension_whitelist) && extension_whitelist
42
+ ActiveSupport::Deprecation.warn "#extension_whitelist is deprecated, use #extension_allowlist instead." unless instance_variable_defined?(:@extension_whitelist_warned)
43
+ @extension_whitelist_warned = true
44
+ allowlist = extension_whitelist
45
+ end
46
+
47
+ return unless allowlist
46
48
 
47
49
  extension = new_file.extension.to_s
48
- if !whitelisted_extension?(extension)
50
+ if !allowlisted_extension?(allowlist, extension)
49
51
  # Look for whitelist first, then fallback to allowlist
50
- raise CarrierWave::IntegrityError, I18n.translate(:"errors.messages.extension_whitelist_error", extension: new_file.extension.inspect,
51
- allowed_types: Array(extension_allowlist).join(", "), default: :"errors.messages.extension_allowlist_error")
52
+ raise CarrierWave::IntegrityError, I18n.translate(:"errors.messages.extension_allowlist_error", extension: new_file.extension.inspect,
53
+ allowed_types: Array(allowlist).join(", "), default: :"errors.messages.extension_whitelist_error")
52
54
  end
53
55
  end
54
56
 
55
- def whitelisted_extension?(extension)
57
+ def allowlisted_extension?(allowlist, extension)
56
58
  downcase_extension = extension.downcase
57
- Array(extension_allowlist).any? { |item| downcase_extension =~ /\A#{item}\z/i }
59
+ Array(allowlist).any? { |item| downcase_extension =~ /\A#{item}\z/i }
58
60
  end
59
- end # ExtensionWhitelist
61
+ end # ExtensionAllowlist
60
62
  end # Uploader
61
63
  end # CarrierWave
@@ -1,10 +1,10 @@
1
1
  module CarrierWave
2
2
  module Uploader
3
- module ExtensionBlacklist
3
+ module ExtensionDenylist
4
4
  extend ActiveSupport::Concern
5
5
 
6
6
  included do
7
- before :cache, :check_extension_blacklist!
7
+ before :cache, :check_extension_denylist!
8
8
  end
9
9
 
10
10
  ##
@@ -32,27 +32,32 @@ module CarrierWave
32
32
  # end
33
33
  #
34
34
  def extension_denylist
35
- if respond_to?(:extension_blacklist)
35
+ end
36
+
37
+ private
38
+
39
+ def check_extension_denylist!(new_file)
40
+ denylist = extension_denylist
41
+ if !denylist && respond_to?(:extension_blacklist) && extension_blacklist
36
42
  ActiveSupport::Deprecation.warn "#extension_blacklist is deprecated, use #extension_denylist instead." unless instance_variable_defined?(:@extension_blacklist_warned)
37
43
  @extension_blacklist_warned = true
38
- extension_blacklist
44
+ denylist = extension_blacklist
39
45
  end
40
- end
41
46
 
42
- private
47
+ return unless denylist
43
48
 
44
- def check_extension_blacklist!(new_file)
45
- return unless extension_denylist
49
+ ActiveSupport::Deprecation.warn "Use of #extension_denylist is deprecated for the security reason, use #extension_allowlist instead to explicitly state what are safe to accept" unless instance_variable_defined?(:@extension_denylist_warned)
50
+ @extension_denylist_warned = true
46
51
 
47
52
  extension = new_file.extension.to_s
48
- if blacklisted_extension?(extension)
49
- raise CarrierWave::IntegrityError, I18n.translate(:"errors.messages.extension_blacklist_error", extension: new_file.extension.inspect,
50
- prohibited_types: Array(extension_denylist).join(", "), default: :"errors.messages.extension_denylist_error")
53
+ if denylisted_extension?(denylist, extension)
54
+ raise CarrierWave::IntegrityError, I18n.translate(:"errors.messages.extension_denylist_error", extension: new_file.extension.inspect,
55
+ prohibited_types: Array(extension_denylist).join(", "), default: :"errors.messages.extension_blacklist_error")
51
56
  end
52
57
  end
53
58
 
54
- def blacklisted_extension?(extension)
55
- Array(extension_denylist).any? { |item| extension =~ /\A#{item}\z/i }
59
+ def denylisted_extension?(denylist, extension)
60
+ Array(denylist).any? { |item| extension =~ /\A#{item}\z/i }
56
61
  end
57
62
  end
58
63
  end
@@ -14,7 +14,7 @@ module CarrierWave
14
14
  # are allowed to be uploaded.
15
15
  # === Returns
16
16
  #
17
- # [NilClass, Range] a size range which are permitted to be uploaded
17
+ # [NilClass, Range] a size range (in bytes) which are permitted to be uploaded
18
18
  #
19
19
  # === Examples
20
20
  #
@@ -24,7 +24,7 @@ module CarrierWave
24
24
  #
25
25
  def size_range; end
26
26
 
27
- private
27
+ private
28
28
 
29
29
  def check_size!(new_file)
30
30
  size = new_file.size
@@ -18,7 +18,7 @@ module CarrierWave
18
18
  # Adds a processor callback which applies operations as a file is uploaded.
19
19
  # The argument may be the name of any method of the uploader, expressed as a symbol,
20
20
  # or a list of such methods, or a hash where the key is a method and the value is
21
- # an array of arguments to call the method with
21
+ # an array of arguments to call the method with. Also accepts an :if or :unless condition
22
22
  #
23
23
  # === Parameters
24
24
  #
@@ -31,6 +31,7 @@ module CarrierWave
31
31
  # process :sepiatone, :vignette
32
32
  # process :scale => [200, 200]
33
33
  # process :scale => [200, 200], :if => :image?
34
+ # process :scale => [200, 200], :unless => :disallowed_image_type?
34
35
  # process :sepiatone, :if => :image?
35
36
  #
36
37
  # def sepiatone
@@ -49,6 +50,10 @@ module CarrierWave
49
50
  # ...
50
51
  # end
51
52
  #
53
+ # def disallowed_image_type?
54
+ # ...
55
+ # end
56
+ #
52
57
  # end
53
58
  #
54
59
  def process(*args)
@@ -57,12 +62,17 @@ module CarrierWave
57
62
  hash.merge!(arg)
58
63
  end
59
64
 
60
- condition = new_processors.delete(:if)
65
+ condition_type = new_processors.keys.detect { |key| [:if, :unless].include?(key) }
66
+ condition = new_processors.delete(:if) || new_processors.delete(:unless)
61
67
  new_processors.each do |processor, processor_args|
62
- self.processors += [[processor, processor_args, condition]]
68
+ self.processors += [[processor, processor_args, condition, condition_type]]
69
+
70
+ if processor == :convert
71
+ # Treat :convert specially, since it should trigger the file extension change
72
+ force_extension processor_args
73
+ end
63
74
  end
64
75
  end
65
-
66
76
  end # ClassMethods
67
77
 
68
78
  ##
@@ -72,13 +82,19 @@ module CarrierWave
72
82
  return unless enable_processing
73
83
 
74
84
  with_callbacks(:process, new_file) do
75
- self.class.processors.each do |method, args, condition|
76
- if(condition)
85
+ self.class.processors.each do |method, args, condition, condition_type|
86
+ if condition && condition_type == :if
77
87
  if condition.respond_to?(:call)
78
88
  next unless condition.call(self, :args => args, :method => method, :file => new_file)
79
89
  else
80
90
  next unless self.send(condition, new_file)
81
91
  end
92
+ elsif condition && condition_type == :unless
93
+ if condition.respond_to?(:call)
94
+ next if condition.call(self, :args => args, :method => method, :file => new_file)
95
+ elsif self.send(condition, new_file)
96
+ next
97
+ end
82
98
  end
83
99
 
84
100
  if args.is_a? Array
@@ -95,6 +111,15 @@ module CarrierWave
95
111
  end
96
112
  end
97
113
 
114
+ private
115
+
116
+ def forcing_extension(filename)
117
+ if force_extension && filename
118
+ Pathname.new(filename).sub_ext(".#{force_extension.to_s.delete_prefix('.')}").to_s
119
+ else
120
+ filename
121
+ end
122
+ end
98
123
  end # Processing
99
124
  end # Uploader
100
125
  end # CarrierWave
@@ -30,7 +30,20 @@ module CarrierWave
30
30
  # [String] uniquely identifies a file
31
31
  #
32
32
  def identifier
33
- @identifier || storage.try(:identifier)
33
+ @identifier || (file && storage.try(:identifier))
34
+ end
35
+
36
+ ##
37
+ # Returns a String which is to be used as a temporary value which gets assigned to the column.
38
+ # The purpose is to mark the column that it will be updated. Finally before the save it will be
39
+ # overwritten by the #identifier value, which is usually #filename.
40
+ #
41
+ # === Returns
42
+ #
43
+ # [String] a temporary_identifier, by default the value of #cache_name is used
44
+ #
45
+ def temporary_identifier
46
+ cache_name || @identifier
34
47
  end
35
48
 
36
49
  ##
@@ -40,8 +53,8 @@ module CarrierWave
40
53
  #
41
54
  # [String] contents of the file
42
55
  #
43
- def read
44
- file.try(:read)
56
+ def read(*args)
57
+ file.try(:read, *args)
45
58
  end
46
59
 
47
60
  ##