carrierwave 1.3.4 → 3.1.4

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.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +278 -86
  3. data/lib/carrierwave/compatibility/paperclip.rb +4 -2
  4. data/lib/carrierwave/downloader/base.rb +101 -0
  5. data/lib/carrierwave/downloader/remote_file.rb +68 -0
  6. data/lib/carrierwave/locale/en.yml +9 -6
  7. data/lib/carrierwave/mount.rb +53 -61
  8. data/lib/carrierwave/mounter.rb +169 -77
  9. data/lib/carrierwave/orm/activerecord.rb +23 -58
  10. data/lib/carrierwave/processing/mini_magick.rb +137 -123
  11. data/lib/carrierwave/processing/rmagick.rb +47 -20
  12. data/lib/carrierwave/processing/vips.rb +315 -0
  13. data/lib/carrierwave/processing.rb +1 -0
  14. data/lib/carrierwave/sanitized_file.rb +91 -70
  15. data/lib/carrierwave/storage/abstract.rb +5 -5
  16. data/lib/carrierwave/storage/file.rb +6 -5
  17. data/lib/carrierwave/storage/fog.rb +114 -62
  18. data/lib/carrierwave/storage.rb +1 -0
  19. data/lib/carrierwave/test/matchers.rb +11 -7
  20. data/lib/carrierwave/uploader/cache.rb +40 -24
  21. data/lib/carrierwave/uploader/callbacks.rb +1 -1
  22. data/lib/carrierwave/uploader/configuration.rb +43 -20
  23. data/lib/carrierwave/uploader/content_type_allowlist.rb +62 -0
  24. data/lib/carrierwave/uploader/content_type_denylist.rb +65 -0
  25. data/lib/carrierwave/uploader/dimension.rb +66 -0
  26. data/lib/carrierwave/uploader/download.rb +2 -123
  27. data/lib/carrierwave/uploader/extension_allowlist.rb +63 -0
  28. data/lib/carrierwave/uploader/extension_denylist.rb +64 -0
  29. data/lib/carrierwave/uploader/file_size.rb +2 -2
  30. data/lib/carrierwave/uploader/mountable.rb +6 -0
  31. data/lib/carrierwave/uploader/processing.rb +45 -7
  32. data/lib/carrierwave/uploader/proxy.rb +17 -4
  33. data/lib/carrierwave/uploader/serialization.rb +1 -1
  34. data/lib/carrierwave/uploader/store.rb +73 -7
  35. data/lib/carrierwave/uploader/url.rb +7 -4
  36. data/lib/carrierwave/uploader/versions.rb +161 -111
  37. data/lib/carrierwave/uploader.rb +10 -17
  38. data/lib/carrierwave/utilities/file_name.rb +47 -0
  39. data/lib/carrierwave/utilities/uri.rb +14 -11
  40. data/lib/carrierwave/utilities.rb +1 -0
  41. data/lib/carrierwave/validations/active_model.rb +7 -9
  42. data/lib/carrierwave/version.rb +1 -1
  43. data/lib/carrierwave.rb +22 -17
  44. data/lib/generators/templates/{uploader.rb → uploader.rb.erb} +13 -4
  45. data/lib/generators/uploader_generator.rb +3 -3
  46. metadata +115 -44
  47. data/lib/carrierwave/uploader/content_type_blacklist.rb +0 -48
  48. data/lib/carrierwave/uploader/content_type_whitelist.rb +0 -48
  49. data/lib/carrierwave/uploader/extension_blacklist.rb +0 -51
  50. data/lib/carrierwave/uploader/extension_whitelist.rb +0 -52
@@ -18,6 +18,8 @@ module CarrierWave
18
18
  # [:fog_use_ssl_for_aws] (optional) #public_url will use https for the AWS generated URL]
19
19
  # [:fog_aws_accelerate] (optional) #public_url will use s3-accelerate subdomain
20
20
  # instead of s3, defaults to false
21
+ # [:fog_aws_fips] (optional) #public_url will use s3-fips subdomain
22
+ # instead of s3, defaults to false
21
23
  #
22
24
  #
23
25
  # AWS credentials contain the following keys:
@@ -30,7 +32,7 @@ module CarrierWave
30
32
  #
31
33
  # Google credentials contain the following keys:
32
34
  # [:google_storage_access_key_id]
33
- # [:google_storage_secrete_access_key]
35
+ # [:google_storage_secret_access_key]
34
36
  #
35
37
  #
36
38
  # Local credentials contain the following keys:
@@ -60,6 +62,14 @@ module CarrierWave
60
62
  def connection_cache
61
63
  @connection_cache ||= {}
62
64
  end
65
+
66
+ def eager_load
67
+ # see #1198. This will hopefully no longer be necessary in future release of fog
68
+ fog_credentials = CarrierWave::Uploader::Base.fog_credentials
69
+ if fog_credentials.present?
70
+ CarrierWave::Storage::Fog.connection_cache[fog_credentials] ||= ::Fog::Storage.new(fog_credentials)
71
+ end
72
+ end
63
73
  end
64
74
 
65
75
  ##
@@ -138,9 +148,10 @@ module CarrierWave
138
148
  :key => uploader.fog_directory,
139
149
  :public => uploader.fog_public
140
150
  ).files.all(:prefix => uploader.cache_dir).each do |file|
141
- # generate_cache_id returns key formated TIMEINT-PID-COUNTER-RND
142
- time = file.key.scan(/(\d+)-\d+-\d+-\d+/).first.map { |t| t.to_i }
143
- time = Time.at(*time)
151
+ # generate_cache_id returns key formatted TIMEINT-PID(-COUNTER)-RND
152
+ matched = file.key.match(/(\d+)-\d+-\d+(?:-\d+)?/)
153
+ next unless matched
154
+ time = Time.at(matched[1].to_i)
144
155
  file.destroy if time < (Time.now.utc - seconds)
145
156
  end
146
157
  end
@@ -153,7 +164,10 @@ module CarrierWave
153
164
  end
154
165
 
155
166
  class File
167
+ DEFAULT_S3_REGION = 'us-east-1'.freeze
168
+
156
169
  include CarrierWave::Utilities::Uri
170
+ include CarrierWave::Utilities::FileName
157
171
 
158
172
  ##
159
173
  # Current local path to file
@@ -177,7 +191,7 @@ module CarrierWave
177
191
 
178
192
  ##
179
193
  # Return a temporary authenticated url to a private file, if available
180
- # Only supported for AWS, Rackspace, Google and AzureRM providers
194
+ # Only supported for AWS, Rackspace, Google, AzureRM and Aliyun providers
181
195
  #
182
196
  # === Returns
183
197
  #
@@ -186,24 +200,27 @@ module CarrierWave
186
200
  # [NilClass] no authenticated url available
187
201
  #
188
202
  def authenticated_url(options = {})
189
- if ['AWS', 'Google', 'Rackspace', 'OpenStack', 'AzureRM'].include?(@uploader.fog_credentials[:provider])
203
+ if ['AWS', 'Google', 'Rackspace', 'OpenStack', 'AzureRM', 'Aliyun', 'backblaze'].include?(fog_provider)
190
204
  # avoid a get by using local references
191
205
  local_directory = connection.directories.new(:key => @uploader.fog_directory)
192
206
  local_file = local_directory.files.new(:key => path)
193
- expire_at = ::Fog::Time.now + @uploader.fog_authenticated_url_expiration
194
- case @uploader.fog_credentials[:provider]
195
- when 'AWS', 'Google'
196
- # Older versions of fog-google do not support options as a parameter
197
- if url_options_supported?(local_file)
198
- local_file.url(expire_at, options)
199
- else
200
- warn "Options hash not supported in #{local_file.class}. You may need to upgrade your Fog provider."
201
- local_file.url(expire_at)
202
- end
203
- when 'Rackspace', 'OpenStack'
204
- connection.get_object_https_url(@uploader.fog_directory, path, expire_at, options)
207
+ expire_at = options[:expire_at] || ::Fog::Time.now.since(@uploader.fog_authenticated_url_expiration.to_i)
208
+ case fog_provider
209
+ when 'AWS', 'Google'
210
+ # Older versions of fog-google do not support options as a parameter
211
+ if url_options_supported?(local_file)
212
+ local_file.url(expire_at, options)
205
213
  else
214
+ warn "Options hash not supported in #{local_file.class}. You may need to upgrade your Fog provider."
206
215
  local_file.url(expire_at)
216
+ end
217
+ when 'Rackspace', 'OpenStack'
218
+ connection.get_object_https_url(@uploader.fog_directory, path, expire_at, options)
219
+ when 'Aliyun'
220
+ expire_at -= Time.now
221
+ local_file.url(expire_at)
222
+ else
223
+ local_file.url(expire_at)
207
224
  end
208
225
  end
209
226
  end
@@ -216,7 +233,7 @@ module CarrierWave
216
233
  # [String] value of content-type
217
234
  #
218
235
  def content_type
219
- @content_type || !file.nil? && file.content_type
236
+ @content_type || file.try(:content_type)
220
237
  end
221
238
 
222
239
  ##
@@ -239,19 +256,9 @@ module CarrierWave
239
256
  #
240
257
  def delete
241
258
  # avoid a get by just using local reference
242
- directory.files.new(:key => path).destroy
243
- end
244
-
245
- ##
246
- # Return extension of file
247
- #
248
- # === Returns
249
- #
250
- # [String] extension of file or nil if the file has no extension
251
- #
252
- def extension
253
- path_elements = path.split('.')
254
- path_elements.last if path_elements.size > 1
259
+ directory.files.new(:key => path).destroy.tap do |result|
260
+ @file = nil if result
261
+ end
255
262
  end
256
263
 
257
264
  ##
@@ -280,16 +287,16 @@ module CarrierWave
280
287
  #
281
288
  # [String] contents of file
282
289
  def read
283
- file_body = file.body
290
+ file_body = file&.body
284
291
 
285
292
  return if file_body.nil?
286
293
  return file_body unless file_body.is_a?(::File)
287
294
 
288
- # Fog::Storage::XXX::File#body could return the source file which was upoloaded to the remote server.
289
- read_source_file(file_body) if ::File.exist?(file_body.path)
295
+ # Fog::Storage::XXX::File#body could return the source file which was uploaded to the remote server.
296
+ return read_source_file if ::File.exist?(file_body.path)
290
297
 
291
298
  # If the source file doesn't exist, the remote content is read
292
- @file = nil # rubocop:disable Gitlab/ModuleWithInstanceVariables
299
+ @file = nil
293
300
  file.body
294
301
  end
295
302
 
@@ -304,6 +311,15 @@ module CarrierWave
304
311
  file.nil? ? 0 : file.content_length
305
312
  end
306
313
 
314
+ ##
315
+ # === Returns
316
+ #
317
+ # [Boolean] whether the file is non-existent or empty
318
+ #
319
+ def empty?
320
+ !exists? || size.zero?
321
+ end
322
+
307
323
  ##
308
324
  # Check if the file exists on the remote service
309
325
  #
@@ -327,7 +343,7 @@ module CarrierWave
327
343
  fog_file = new_file.to_file
328
344
  @content_type ||= new_file.content_type
329
345
  @file = directory.files.create({
330
- :body => fog_file ? fog_file : new_file.read,
346
+ :body => fog_file || new_file.read,
331
347
  :content_type => @content_type,
332
348
  :key => path,
333
349
  :public => @uploader.fog_public
@@ -348,7 +364,7 @@ module CarrierWave
348
364
  #
349
365
  def public_url
350
366
  encoded_path = encode_path(path)
351
- if host = @uploader.asset_host
367
+ if (host = @uploader.asset_host)
352
368
  if host.respond_to? :call
353
369
  "#{host.call(self)}/#{encoded_path}"
354
370
  else
@@ -360,20 +376,29 @@ module CarrierWave
360
376
  when 'AWS'
361
377
  # check if some endpoint is set in fog_credentials
362
378
  if @uploader.fog_credentials.has_key?(:endpoint)
379
+ raise 'fog_aws_fips = true is incompatible with :endpoint, as FIPS endpoints do not support path-style URLs.' if @uploader.fog_aws_fips
363
380
  "#{@uploader.fog_credentials[:endpoint]}/#{@uploader.fog_directory}/#{encoded_path}"
364
381
  else
365
382
  protocol = @uploader.fog_use_ssl_for_aws ? "https" : "http"
366
383
 
367
384
  subdomain_regex = /^(?:[a-z]|\d(?!\d{0,2}(?:\d{1,3}){3}$))(?:[a-z0-9\.]|(?![\-])|\-(?![\.])){1,61}[a-z0-9]$/
368
- valid_subdomain = @uploader.fog_directory.to_s =~ subdomain_regex && !(protocol == 'https' && @uploader.fog_directory =~ /\./)
369
-
370
- # if directory is a valid subdomain, use that style for access
371
- if valid_subdomain
372
- s3_subdomain = @uploader.fog_aws_accelerate ? "s3-accelerate" : "s3"
373
- "#{protocol}://#{@uploader.fog_directory}.#{s3_subdomain}.amazonaws.com/#{encoded_path}"
374
- else
375
- # directory is not a valid subdomain, so use path style for access
376
- "#{protocol}://s3.amazonaws.com/#{@uploader.fog_directory}/#{encoded_path}"
385
+ # To use the virtual-hosted style, the bucket name needs to be representable as a subdomain
386
+ use_virtual_hosted_style = @uploader.fog_directory.to_s =~ subdomain_regex && !(protocol == 'https' && @uploader.fog_directory =~ /\./)
387
+
388
+ region = @uploader.fog_credentials[:region].to_s
389
+ regional_host = 's3.amazonaws.com' # used for DEFAULT_S3_REGION or no region set
390
+ if @uploader.fog_aws_fips
391
+ regional_host = "s3-fips.#{region}.amazonaws.com" # https://aws.amazon.com/compliance/fips/
392
+ elsif ![DEFAULT_S3_REGION, ''].include?(region)
393
+ regional_host = "s3.#{region}.amazonaws.com"
394
+ end
395
+
396
+ if use_virtual_hosted_style
397
+ regional_host = 's3-accelerate.amazonaws.com' if @uploader.fog_aws_accelerate
398
+ "#{protocol}://#{@uploader.fog_directory}.#{regional_host}/#{encoded_path}"
399
+ else # directory is not a valid subdomain, so use path style for access
400
+ raise 'FIPS Endpoints can only be used with Virtual Hosted-Style addressing.' if @uploader.fog_aws_fips
401
+ "#{protocol}://#{regional_host}/#{@uploader.fog_directory}/#{encoded_path}"
377
402
  end
378
403
  end
379
404
  when 'Google'
@@ -387,7 +412,7 @@ module CarrierWave
387
412
  end
388
413
 
389
414
  ##
390
- # Return url to file, if avaliable
415
+ # Return url to file, if available
391
416
  #
392
417
  # === Returns
393
418
  #
@@ -413,7 +438,7 @@ module CarrierWave
413
438
  # [NilClass] no file name available
414
439
  #
415
440
  def filename(options = {})
416
- return unless file_url = url(options)
441
+ return unless (file_url = url(options))
417
442
  CGI.unescape(file_url.split('?').first).gsub(/.*\/(.*?$)/, '\1')
418
443
  end
419
444
 
@@ -429,10 +454,29 @@ module CarrierWave
429
454
  # @return [CarrierWave::Storage::Fog::File] the location where the file will be stored.
430
455
  #
431
456
  def copy_to(new_path)
432
- connection.copy_object(@uploader.fog_directory, file.key, @uploader.fog_directory, new_path, acl_header)
457
+ file.copy(@uploader.fog_directory, new_path, copy_options)
433
458
  CarrierWave::Storage::Fog::File.new(@uploader, @base, new_path)
434
459
  end
435
460
 
461
+ ##
462
+ # Return the local file
463
+ #
464
+ # === Returns
465
+ #
466
+ # [File] The local file as Ruby's File class
467
+ # or
468
+ # [NilClass] When there's no file, or the file is remotely stored
469
+ #
470
+ def to_file
471
+ return nil unless file.body.is_a? ::File
472
+
473
+ if file.body.closed?
474
+ ::File.open(file.body.path) # Reopen if it's already closed
475
+ else
476
+ file.body
477
+ end
478
+ end
479
+
436
480
  private
437
481
 
438
482
  ##
@@ -454,12 +498,10 @@ module CarrierWave
454
498
  # [Fog::#{provider}::Directory] containing directory
455
499
  #
456
500
  def directory
457
- @directory ||= begin
458
- connection.directories.new(
459
- :key => @uploader.fog_directory,
460
- :public => @uploader.fog_public
461
- )
462
- end
501
+ @directory ||= connection.directories.new(
502
+ :key => @uploader.fog_directory,
503
+ :public => @uploader.fog_public
504
+ )
463
505
  end
464
506
 
465
507
  ##
@@ -473,9 +515,19 @@ module CarrierWave
473
515
  @file ||= directory.files.head(path)
474
516
  end
475
517
 
518
+ def copy_options
519
+ options = {}
520
+ options.merge!(acl_header) if acl_header.present?
521
+ options[fog_provider == "Google" ? :content_type : 'Content-Type'] ||= content_type if content_type
522
+ options.merge(@uploader.fog_attributes)
523
+ end
524
+
476
525
  def acl_header
477
- if fog_provider == 'AWS'
526
+ case fog_provider
527
+ when 'AWS'
478
528
  { 'x-amz-acl' => @uploader.fog_public ? 'public-read' : 'private' }
529
+ when "Google"
530
+ @uploader.fog_public ? { destination_predefined_acl: "publicRead" } : {}
479
531
  else
480
532
  {}
481
533
  end
@@ -485,14 +537,14 @@ module CarrierWave
485
537
  @uploader.fog_credentials[:provider].to_s
486
538
  end
487
539
 
488
- def read_source_file(file_body)
489
- return unless ::File.exist?(file_body.path)
540
+ def read_source_file
541
+ source_file = to_file
542
+ return unless source_file
490
543
 
491
544
  begin
492
- file_body = ::File.open(file_body.path) if file_body.closed? # Reopen if it's already closed
493
- file_body.read
545
+ source_file.read
494
546
  ensure
495
- file_body.close
547
+ source_file.close
496
548
  end
497
549
  end
498
550
 
@@ -1,2 +1,3 @@
1
1
  require "carrierwave/storage/abstract"
2
2
  require "carrierwave/storage/file"
3
+ require "carrierwave/storage/fog"
@@ -45,11 +45,11 @@ module CarrierWave
45
45
  def matches?(actual)
46
46
  @actual = actual
47
47
  # Satisfy expectation here. Return false or raise an error if it's not met.
48
- (File.stat(@actual.path).mode & 0777) == @expected
48
+ (File.stat(@actual.path).mode & 0o777) == @expected
49
49
  end
50
50
 
51
51
  def failure_message
52
- "expected #{@actual.current_path.inspect} to have permissions #{@expected.to_s(8)}, but they were #{(File.stat(@actual.path).mode & 0777).to_s(8)}"
52
+ "expected #{@actual.current_path.inspect} to have permissions #{@expected.to_s(8)}, but they were #{(File.stat(@actual.path).mode & 0o777).to_s(8)}"
53
53
  end
54
54
 
55
55
  def failure_message_when_negated
@@ -76,11 +76,11 @@ module CarrierWave
76
76
  def matches?(actual)
77
77
  @actual = actual
78
78
  # Satisfy expectation here. Return false or raise an error if it's not met.
79
- (File.stat(File.dirname @actual.path).mode & 0777) == @expected
79
+ (File.stat(File.dirname(@actual.path)).mode & 0o777) == @expected
80
80
  end
81
81
 
82
82
  def failure_message
83
- "expected #{File.dirname @actual.current_path.inspect} to have permissions #{@expected.to_s(8)}, but they were #{(File.stat(@actual.path).mode & 0777).to_s(8)}"
83
+ "expected #{File.dirname @actual.current_path.inspect} to have permissions #{@expected.to_s(8)}, but they were #{(File.stat(@actual.path).mode & 0o777).to_s(8)}"
84
84
  end
85
85
 
86
86
  def failure_message_when_negated
@@ -341,9 +341,11 @@ module CarrierWave
341
341
  begin
342
342
  require 'rmagick'
343
343
  rescue LoadError
344
- require 'RMagick'
345
- rescue LoadError
346
- puts "WARNING: Failed to require rmagick, image processing may fail!"
344
+ begin
345
+ require 'RMagick'
346
+ rescue LoadError
347
+ puts "WARNING: Failed to require rmagick, image processing may fail!"
348
+ end
347
349
  end
348
350
  end
349
351
  MagickWrapper.new(filename)
@@ -353,6 +355,7 @@ module CarrierWave
353
355
 
354
356
  class MagickWrapper # :nodoc:
355
357
  attr_reader :image
358
+
356
359
  def width
357
360
  image.columns
358
361
  end
@@ -372,6 +375,7 @@ module CarrierWave
372
375
 
373
376
  class MiniMagickWrapper # :nodoc:
374
377
  attr_reader :image
378
+
375
379
  def width
376
380
  image[:width]
377
381
  end
@@ -1,3 +1,5 @@
1
+ require 'securerandom'
2
+
1
3
  module CarrierWave
2
4
 
3
5
  class FormNotMultipart < UploadError
@@ -22,10 +24,11 @@ module CarrierWave
22
24
  # [String] a cache id in the format TIMEINT-PID-COUNTER-RND
23
25
  #
24
26
  def self.generate_cache_id
25
- [Time.now.utc.to_i,
26
- Process.pid,
27
- '%04d' % (CarrierWave::CacheCounter.increment % 1000),
28
- '%04d' % rand(9999)
27
+ [
28
+ Time.now.utc.to_i,
29
+ SecureRandom.random_number(1_000_000_000_000_000),
30
+ '%04d' % (CarrierWave::CacheCounter.increment % 10_000),
31
+ '%04d' % SecureRandom.random_number(10_000)
29
32
  ].map(&:to_s).join('-')
30
33
  end
31
34
 
@@ -36,6 +39,16 @@ module CarrierWave
36
39
  include CarrierWave::Uploader::Callbacks
37
40
  include CarrierWave::Uploader::Configuration
38
41
 
42
+ included do
43
+ prepend Module.new {
44
+ def initialize(*)
45
+ super
46
+ @staged = false
47
+ end
48
+ }
49
+ attr_accessor :staged
50
+ end
51
+
39
52
  module ClassMethods
40
53
 
41
54
  ##
@@ -52,7 +65,7 @@ module CarrierWave
52
65
  # It's recommended that you keep cache files in one place only.
53
66
  #
54
67
  def clean_cached_files!(seconds=60*60*24)
55
- cache_storage.new(CarrierWave::Uploader::Base.new).clean_cache!(seconds)
68
+ (cache_storage || storage).new(new).clean_cache!(seconds)
56
69
  end
57
70
  end
58
71
 
@@ -64,7 +77,7 @@ module CarrierWave
64
77
  # [Bool] whether the current file is cached
65
78
  #
66
79
  def cached?
67
- @cache_id
80
+ !!@cache_id
68
81
  end
69
82
 
70
83
  ##
@@ -78,15 +91,9 @@ module CarrierWave
78
91
  end
79
92
 
80
93
  def sanitized_file
81
- _content = file.read
82
- if _content.is_a?(File) # could be if storage is Fog
83
- sanitized = CarrierWave::Storage::Fog.new(self).retrieve!(File.basename(_content.path))
84
- else
85
- sanitized = SanitizedFile.new :tempfile => StringIO.new(_content),
86
- :filename => File.basename(path), :content_type => file.content_type
87
- end
88
- sanitized
94
+ file
89
95
  end
96
+ CarrierWave.deprecator.deprecate_methods(self, sanitized_file: :file)
90
97
 
91
98
  ##
92
99
  # Returns a String which uniquely identifies the currently cached file for later retrieval
@@ -96,7 +103,7 @@ module CarrierWave
96
103
  # [String] a cache name, in the format TIMEINT-PID-COUNTER-RND/filename.txt
97
104
  #
98
105
  def cache_name
99
- File.join(cache_id, full_original_filename) if cache_id and original_filename
106
+ File.join(cache_id, original_filename) if cache_id && original_filename
100
107
  end
101
108
 
102
109
  ##
@@ -104,7 +111,7 @@ module CarrierWave
104
111
  #
105
112
  # By default, cache!() uses copy_to(), which operates by copying the file
106
113
  # to the cache, then deleting the original file. If move_to_cache() is
107
- # overriden to return true, then cache!() uses move_to(), which simply
114
+ # overridden to return true, then cache!() uses move_to(), which simply
108
115
  # moves the file to the cache. Useful for large files.
109
116
  #
110
117
  # === Parameters
@@ -115,7 +122,7 @@ module CarrierWave
115
122
  #
116
123
  # [CarrierWave::FormNotMultipart] if the assigned parameter is a string
117
124
  #
118
- def cache!(new_file = sanitized_file)
125
+ def cache!(new_file = file)
119
126
  new_file = CarrierWave::SanitizedFile.new(new_file)
120
127
  return if new_file.empty?
121
128
 
@@ -123,6 +130,8 @@ module CarrierWave
123
130
 
124
131
  self.cache_id = CarrierWave.generate_cache_id unless cache_id
125
132
 
133
+ @identifier = nil
134
+ @staged = true
126
135
  @filename = new_file.filename
127
136
  self.original_filename = new_file.filename
128
137
 
@@ -156,8 +165,9 @@ module CarrierWave
156
165
  def retrieve_from_cache!(cache_name)
157
166
  with_callbacks(:retrieve_from_cache, cache_name) do
158
167
  self.cache_id, self.original_filename = cache_name.to_s.split('/', 2)
168
+ @staged = true
159
169
  @filename = original_filename
160
- @file = cache_storage.retrieve_from_cache!(full_filename(original_filename))
170
+ @file = cache_storage.retrieve_from_cache!(full_original_filename)
161
171
  end
162
172
  end
163
173
 
@@ -172,20 +182,21 @@ module CarrierWave
172
182
  #
173
183
  # [String] the cache path
174
184
  #
175
- def cache_path(for_file=full_filename(original_filename))
185
+ def cache_path(for_file=full_original_filename)
176
186
  File.join(*[cache_dir, @cache_id, for_file].compact)
177
187
  end
178
188
 
189
+ protected
190
+
191
+ attr_reader :cache_id
192
+
179
193
  private
180
194
 
181
195
  def workfile_path(for_file=original_filename)
182
196
  File.join(CarrierWave.tmp_path, @cache_id, version_name.to_s, for_file)
183
197
  end
184
198
 
185
- attr_reader :cache_id, :original_filename
186
-
187
- # We can override the full_original_filename method in other modules
188
- alias_method :full_original_filename, :original_filename
199
+ attr_reader :original_filename
189
200
 
190
201
  def cache_id=(cache_id)
191
202
  # Earlier version used 3 part cache_id. Thus we should allow for
@@ -200,7 +211,12 @@ module CarrierWave
200
211
  end
201
212
 
202
213
  def cache_storage
203
- @cache_storage ||= self.class.cache_storage.new(self)
214
+ @cache_storage ||= (self.class.cache_storage || self.class.storage).new(self)
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)
204
220
  end
205
221
  end # Cache
206
222
  end # Uploader
@@ -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