carrierwave 1.3.1 → 3.0.5

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 (50) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +238 -91
  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 +167 -77
  9. data/lib/carrierwave/orm/activerecord.rb +15 -55
  10. data/lib/carrierwave/processing/mini_magick.rb +108 -123
  11. data/lib/carrierwave/processing/rmagick.rb +20 -18
  12. data/lib/carrierwave/processing/vips.rb +284 -0
  13. data/lib/carrierwave/processing.rb +1 -0
  14. data/lib/carrierwave/sanitized_file.rb +66 -73
  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 +101 -64
  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 +38 -19
  23. data/lib/carrierwave/uploader/content_type_allowlist.rb +62 -0
  24. data/lib/carrierwave/uploader/content_type_denylist.rb +62 -0
  25. data/lib/carrierwave/uploader/dimension.rb +66 -0
  26. data/lib/carrierwave/uploader/download.rb +2 -80
  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 +42 -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 +47 -7
  35. data/lib/carrierwave/uploader/url.rb +7 -4
  36. data/lib/carrierwave/uploader/versions.rb +153 -105
  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 +13 -17
  44. data/lib/generators/templates/{uploader.rb → uploader.rb.erb} +3 -3
  45. data/lib/generators/uploader_generator.rb +3 -3
  46. metadata +104 -38
  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
@@ -11,7 +11,7 @@ module CarrierWave
11
11
  prepend Module.new {
12
12
  def initialize(*)
13
13
  super
14
- @file, @filename, @cache_id = nil
14
+ @file, @filename, @cache_id, @identifier, @deduplication_index = nil
15
15
  end
16
16
  }
17
17
  end
@@ -34,9 +34,26 @@ module CarrierWave
34
34
  @filename
35
35
  end
36
36
 
37
+ ##
38
+ # Returns a filename which doesn't conflict with already-stored files.
39
+ #
40
+ # === Returns
41
+ #
42
+ # [String] the filename with suffix added for deduplication
43
+ #
44
+ def deduplicated_filename
45
+ return unless filename
46
+ return filename unless @deduplication_index
47
+
48
+ parts = filename.split('.')
49
+ basename = parts.shift
50
+ basename.sub!(/ ?\(\d+\)\z/, '')
51
+ ([basename.to_s + (@deduplication_index > 1 ? "(#{@deduplication_index})" : '')] + parts).join('.')
52
+ end
53
+
37
54
  ##
38
55
  # Calculates the path where the file should be stored. If +for_file+ is given, it will be
39
- # used as the filename, otherwise +CarrierWave::Uploader#filename+ is assumed.
56
+ # used as the identifier, otherwise +CarrierWave::Uploader#identifier+ is assumed.
40
57
  #
41
58
  # === Parameters
42
59
  #
@@ -46,7 +63,7 @@ module CarrierWave
46
63
  #
47
64
  # [String] the store path
48
65
  #
49
- def store_path(for_file=filename)
66
+ def store_path(for_file=identifier)
50
67
  File.join([store_dir, full_filename(for_file)].compact)
51
68
  end
52
69
 
@@ -60,8 +77,8 @@ module CarrierWave
60
77
  # [new_file (File, IOString, Tempfile)] any kind of file object
61
78
  #
62
79
  def store!(new_file=nil)
63
- cache!(new_file) if new_file && ((@cache_id != parent_cache_id) || @cache_id.nil?)
64
- if !cache_only and @file and @cache_id
80
+ cache!(new_file) if new_file && !cached?
81
+ if !cache_only && @file && @cache_id
65
82
  with_callbacks(:store, new_file) do
66
83
  new_file = storage.store!(@file)
67
84
  if delete_tmp_file_after_storage
@@ -69,7 +86,9 @@ module CarrierWave
69
86
  cache_storage.delete_dir!(cache_path(nil))
70
87
  end
71
88
  @file = new_file
72
- @cache_id = nil
89
+ @identifier = storage.identifier
90
+ @original_filename = @cache_id = @deduplication_index = nil
91
+ @staged = false
73
92
  end
74
93
  end
75
94
  end
@@ -84,13 +103,34 @@ module CarrierWave
84
103
  def retrieve_from_store!(identifier)
85
104
  with_callbacks(:retrieve_from_store, identifier) do
86
105
  @file = storage.retrieve!(identifier)
106
+ @identifier = identifier
107
+ end
108
+ end
109
+
110
+ ##
111
+ # Look for an identifier which doesn't collide with the given already-stored identifiers.
112
+ # It is done by adding a index number as the suffix.
113
+ # For example, if there's 'image.jpg' and the @deduplication_index is set to 2,
114
+ # The stored file will be named as 'image(2).jpg'.
115
+ #
116
+ # === Parameters
117
+ #
118
+ # [current_identifiers (Array[String])] List of identifiers for already-stored files
119
+ #
120
+ def deduplicate(current_identifiers)
121
+ @deduplication_index = nil
122
+ return unless current_identifiers.include?(identifier)
123
+
124
+ (1..current_identifiers.size + 1).each do |i|
125
+ @deduplication_index = i
126
+ break unless current_identifiers.include?(identifier)
87
127
  end
88
128
  end
89
129
 
90
130
  private
91
131
 
92
132
  def full_filename(for_file)
93
- for_file
133
+ forcing_extension(for_file)
94
134
  end
95
135
 
96
136
  def storage
@@ -15,12 +15,15 @@ module CarrierWave
15
15
  # [String] the location where this file is accessible via a url
16
16
  #
17
17
  def url(options = {})
18
- if file.respond_to?(:url) and not (tmp_url = file.url).blank?
19
- file.method(:url).arity == 0 ? tmp_url : file.url(options)
20
- elsif file.respond_to?(:path)
18
+ if file.respond_to?(:url)
19
+ tmp_url = file.method(:url).arity.zero? ? file.url : file.url(options)
20
+ return tmp_url if tmp_url.present?
21
+ end
22
+
23
+ if file.respond_to?(:path)
21
24
  path = encode_path(file.path.sub(File.expand_path(root), ''))
22
25
 
23
- if host = asset_host
26
+ if (host = asset_host)
24
27
  if host.respond_to? :call
25
28
  "#{host.call(file)}#{path}"
26
29
  else
@@ -1,6 +1,89 @@
1
+ require "active_support/core_ext/object/deep_dup"
2
+
1
3
  module CarrierWave
2
4
  module Uploader
3
5
  module Versions
6
+ class Builder
7
+ def initialize(name)
8
+ @name = name
9
+ @options = {}
10
+ @blocks = []
11
+ @klass = nil
12
+ end
13
+
14
+ def configure(options, &block)
15
+ @options.merge!(options)
16
+ @blocks << block if block
17
+ @klass = nil
18
+ end
19
+
20
+ def build(superclass)
21
+ return @klass if @klass
22
+ @klass = Class.new(superclass)
23
+ superclass.const_set("#{@name.to_s.camelize}VersionUploader", @klass)
24
+
25
+ @klass.version_names += [@name]
26
+ @klass.versions = {}
27
+ @klass.processors = []
28
+ @klass.version_options = @options
29
+ @klass.class_eval <<-RUBY, __FILE__, __LINE__ + 1
30
+ # Define the enable_processing method for versions so they get the
31
+ # value from the parent class unless explicitly overwritten
32
+ def self.enable_processing(value=nil)
33
+ self.enable_processing = value if value
34
+ if defined?(@enable_processing) && !@enable_processing.nil?
35
+ @enable_processing
36
+ else
37
+ superclass.enable_processing
38
+ end
39
+ end
40
+
41
+ # Regardless of what is set in the parent uploader, do not enforce the
42
+ # move_to_cache config option on versions because it moves the original
43
+ # file to the version's target file.
44
+ #
45
+ # If you want to enforce this setting on versions, override this method
46
+ # in each version:
47
+ #
48
+ # version :thumb do
49
+ # def move_to_cache
50
+ # true
51
+ # end
52
+ # end
53
+ #
54
+ def move_to_cache
55
+ false
56
+ end
57
+
58
+ # Need to rely on the parent version's identifier, as versions don't have its own one.
59
+ def identifier
60
+ parent_version.identifier
61
+ end
62
+ RUBY
63
+ @blocks.each { |block| @klass.class_eval(&block) }
64
+ @klass
65
+ end
66
+
67
+ def deep_dup
68
+ other = dup
69
+ other.instance_variable_set(:@blocks, @blocks.dup)
70
+ other
71
+ end
72
+
73
+ def method_missing(name, *args)
74
+ super
75
+ rescue NoMethodError => e
76
+ raise e.exception <<~ERROR
77
+ #{e.message}
78
+ If you're trying to configure a version, do it inside a block like `version(:thumb) { self.#{name} #{args.map(&:inspect).join(', ')} }`.
79
+ ERROR
80
+ end
81
+
82
+ def respond_to_missing?(*)
83
+ super
84
+ end
85
+ end
86
+
4
87
  extend ActiveSupport::Concern
5
88
 
6
89
  include CarrierWave::Uploader::Callbacks
@@ -11,9 +94,8 @@ module CarrierWave
11
94
  self.versions = {}
12
95
  self.version_names = []
13
96
 
14
- attr_accessor :parent_cache_id, :parent_version
97
+ attr_accessor :parent_version
15
98
 
16
- after :cache, :assign_parent_cache_id
17
99
  after :cache, :cache_versions!
18
100
  after :store, :store_versions!
19
101
  after :remove, :remove_versions!
@@ -51,80 +133,33 @@ module CarrierWave
51
133
  # process :scale => [200, 200]
52
134
  # end
53
135
  #
136
+ # version :square, :unless => :invalid_image_type? do
137
+ # process :scale => [100, 100]
138
+ # end
139
+ #
54
140
  # end
55
141
  #
56
142
  def version(name, options = {}, &block)
57
143
  name = name.to_sym
58
- build_version(name, options)
144
+ versions[name] ||= Builder.new(name)
145
+ versions[name].configure(options, &block)
59
146
 
60
- versions[name].class_eval(&block) if block
61
- versions[name]
62
- end
147
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
148
+ def #{name}
149
+ versions[:#{name}]
150
+ end
151
+ RUBY
63
152
 
64
- def recursively_apply_block_to_versions(&block)
65
- versions.each do |name, version|
66
- version.class_eval(&block)
67
- version.recursively_apply_block_to_versions(&block)
68
- end
153
+ versions[name]
69
154
  end
70
155
 
71
156
  private
72
157
 
73
- def build_version(name, options)
74
- if !versions.has_key?(name)
75
- uploader = Class.new(self)
76
- const_set("Uploader#{uploader.object_id}".tr('-', '_'), uploader)
77
- uploader.version_names += [name]
78
- uploader.versions = {}
79
- uploader.processors = []
80
- uploader.version_options = options
81
-
82
- uploader.class_eval <<-RUBY, __FILE__, __LINE__ + 1
83
- # Define the enable_processing method for versions so they get the
84
- # value from the parent class unless explicitly overwritten
85
- def self.enable_processing(value=nil)
86
- self.enable_processing = value if value
87
- if defined?(@enable_processing) && !@enable_processing.nil?
88
- @enable_processing
89
- else
90
- superclass.enable_processing
91
- end
92
- end
93
-
94
- # Regardless of what is set in the parent uploader, do not enforce the
95
- # move_to_cache config option on versions because it moves the original
96
- # file to the version's target file.
97
- #
98
- # If you want to enforce this setting on versions, override this method
99
- # in each version:
100
- #
101
- # version :thumb do
102
- # def move_to_cache
103
- # true
104
- # end
105
- # end
106
- #
107
- def move_to_cache
108
- false
109
- end
110
- RUBY
111
-
112
- class_eval <<-RUBY, __FILE__, __LINE__ + 1
113
- def #{name}
114
- versions[:#{name}]
115
- end
116
- RUBY
117
- else
118
- uploader = Class.new(versions[name])
119
- const_set("Uploader#{uploader.object_id}".tr('-', '_'), uploader)
120
- uploader.processors = []
121
- uploader.version_options = uploader.version_options.merge(options)
122
- end
123
-
124
- # Add the current version hash to class attribute :versions
125
- self.versions = versions.merge(name => uploader)
158
+ def inherited(subclass)
159
+ # To prevent subclass version changes affecting superclass versions
160
+ subclass.versions = versions.deep_dup
161
+ super
126
162
  end
127
-
128
163
  end # ClassMethods
129
164
 
130
165
  ##
@@ -138,7 +173,7 @@ module CarrierWave
138
173
  return @versions if @versions
139
174
  @versions = {}
140
175
  self.class.versions.each do |name, version|
141
- @versions[name] = version.new(model, mounted_as)
176
+ @versions[name] = version.build(self.class).new(model, mounted_as)
142
177
  @versions[name].parent_version = self
143
178
  end
144
179
  @versions
@@ -161,25 +196,44 @@ module CarrierWave
161
196
  #
162
197
  # === Returns
163
198
  #
164
- # [Boolean] True when the version exists according to its :if condition
199
+ # [Boolean] True when the version exists according to its :if or :unless condition
165
200
  #
166
201
  def version_exists?(name)
167
202
  name = name.to_sym
168
203
 
169
- return false unless self.class.versions.has_key?(name)
204
+ return false unless versions.has_key?(name)
170
205
 
171
- condition = self.class.versions[name].version_options[:if]
172
- if(condition)
173
- if(condition.respond_to?(:call))
174
- condition.call(self, :version => name, :file => file)
206
+ if_condition = versions[name].class.version_options[:if]
207
+ unless_condition = versions[name].class.version_options[:unless]
208
+
209
+ if if_condition
210
+ if if_condition.respond_to?(:call)
211
+ if_condition.call(self, :version => name, :file => file)
212
+ else
213
+ send(if_condition, file)
214
+ end
215
+ elsif unless_condition
216
+ if unless_condition.respond_to?(:call)
217
+ !unless_condition.call(self, :version => name, :file => file)
175
218
  else
176
- send(condition, file)
219
+ !send(unless_condition, file)
177
220
  end
178
221
  else
179
222
  true
180
223
  end
181
224
  end
182
225
 
226
+ ##
227
+ # Copies the parent's cache_id when caching a version file.
228
+ # This behavior is not essential but it makes easier to understand
229
+ # that the cached files are generated by the single upload attempt.
230
+ #
231
+ def cache!(*args)
232
+ self.cache_id = parent_version.cache_id if parent_version
233
+
234
+ super
235
+ end
236
+
183
237
  ##
184
238
  # When given a version name as a parameter, will return the url for that version
185
239
  # This also works with nested versions.
@@ -220,26 +274,26 @@ module CarrierWave
220
274
  # Recreate versions and reprocess them. This can be used to recreate
221
275
  # versions if their parameters somehow have changed.
222
276
  #
223
- def recreate_versions!(*versions)
224
- # Some files could possibly not be stored on the local disk. This
225
- # doesn't play nicely with processing. Make sure that we're only
226
- # processing a cached file
227
- #
228
- # The call to store! will trigger the necessary callbacks to both
229
- # process this version and all sub-versions
230
- if versions.any?
231
- file = sanitized_file if !cached?
232
- store_versions!(file, versions)
233
- else
234
- cache! if !cached?
235
- store!
277
+ def recreate_versions!(*names)
278
+ # As well as specified versions, we need to reprocess versions
279
+ # that are the source of another version.
280
+
281
+ self.cache_id = CarrierWave.generate_cache_id
282
+ derived_versions.each do |name, v|
283
+ v.cache!(file) if names.empty? || !(v.descendant_version_names & names).empty?
284
+ end
285
+ active_versions.each do |name, v|
286
+ v.store! if names.empty? || names.include?(name)
236
287
  end
288
+ ensure
289
+ @cache_id = nil
237
290
  end
238
291
 
239
- private
240
- def assign_parent_cache_id(file)
241
- active_versions.each do |name, uploader|
242
- uploader.parent_cache_id = @cache_id
292
+ protected
293
+
294
+ def descendant_version_names
295
+ [version_name] + derived_versions.flat_map do |name, version|
296
+ version.descendant_version_names
243
297
  end
244
298
  end
245
299
 
@@ -249,16 +303,18 @@ module CarrierWave
249
303
  end
250
304
  end
251
305
 
252
- def dependent_versions
306
+ private
307
+
308
+ def derived_versions
253
309
  active_versions.reject do |name, v|
254
310
  v.class.version_options[:from_version]
255
- end.to_a + sibling_versions.select do |name, v|
311
+ end.to_a + active_sibling_versions.select do |name, v|
256
312
  v.class.version_options[:from_version] == self.class.version_names.last
257
313
  end.to_a
258
314
  end
259
315
 
260
- def sibling_versions
261
- parent_version.try(:versions) || []
316
+ def active_sibling_versions
317
+ parent_version&.active_versions || []
262
318
  end
263
319
 
264
320
  def full_filename(for_file)
@@ -270,19 +326,11 @@ module CarrierWave
270
326
  end
271
327
 
272
328
  def cache_versions!(new_file)
273
- dependent_versions.each do |name, v|
274
- v.send(:cache_id=, @cache_id)
275
- v.cache!(new_file)
276
- end
329
+ derived_versions.each { |name, v| v.cache!(new_file) }
277
330
  end
278
331
 
279
- def store_versions!(new_file, versions=nil)
280
- if versions
281
- active = Hash[active_versions]
282
- versions.each { |v| active[v].try(:store!, new_file) } unless active.empty?
283
- else
284
- active_versions.each { |name, v| v.store!(new_file) }
285
- end
332
+ def store_versions!(new_file)
333
+ active_versions.each { |name, v| v.store!(new_file) }
286
334
  end
287
335
 
288
336
  def remove_versions!
@@ -7,11 +7,12 @@ require "carrierwave/uploader/cache"
7
7
  require "carrierwave/uploader/store"
8
8
  require "carrierwave/uploader/download"
9
9
  require "carrierwave/uploader/remove"
10
- require "carrierwave/uploader/extension_whitelist"
11
- require "carrierwave/uploader/extension_blacklist"
12
- require "carrierwave/uploader/content_type_whitelist"
13
- require "carrierwave/uploader/content_type_blacklist"
10
+ require "carrierwave/uploader/extension_allowlist"
11
+ require "carrierwave/uploader/extension_denylist"
12
+ require "carrierwave/uploader/content_type_allowlist"
13
+ require "carrierwave/uploader/content_type_denylist"
14
14
  require "carrierwave/uploader/file_size"
15
+ require "carrierwave/uploader/dimension"
15
16
  require "carrierwave/uploader/processing"
16
17
  require "carrierwave/uploader/versions"
17
18
  require "carrierwave/uploader/default_url"
@@ -43,15 +44,6 @@ module CarrierWave
43
44
  class Base
44
45
  attr_reader :file
45
46
 
46
- ##
47
- # Workaround for class_attribute malfunction when used with Module#prepend
48
- #
49
- if RUBY_VERSION < '2.1.0'
50
- def self.singleton_class?
51
- !ancestors.include? self
52
- end
53
- end
54
-
55
47
  include CarrierWave::Uploader::Configuration
56
48
  include CarrierWave::Uploader::Callbacks
57
49
  include CarrierWave::Uploader::Proxy
@@ -61,11 +53,12 @@ module CarrierWave
61
53
  include CarrierWave::Uploader::Store
62
54
  include CarrierWave::Uploader::Download
63
55
  include CarrierWave::Uploader::Remove
64
- include CarrierWave::Uploader::ExtensionWhitelist
65
- include CarrierWave::Uploader::ExtensionBlacklist
66
- include CarrierWave::Uploader::ContentTypeWhitelist
67
- include CarrierWave::Uploader::ContentTypeBlacklist
56
+ include CarrierWave::Uploader::ExtensionAllowlist
57
+ include CarrierWave::Uploader::ExtensionDenylist
58
+ include CarrierWave::Uploader::ContentTypeAllowlist
59
+ include CarrierWave::Uploader::ContentTypeDenylist
68
60
  include CarrierWave::Uploader::FileSize
61
+ include CarrierWave::Uploader::Dimension
69
62
  include CarrierWave::Uploader::Processing
70
63
  include CarrierWave::Uploader::Versions
71
64
  include CarrierWave::Uploader::DefaultUrl
@@ -0,0 +1,47 @@
1
+ module CarrierWave
2
+ module Utilities
3
+ module FileName
4
+
5
+ ##
6
+ # Returns the part of the filename before the extension. So if a file is called 'test.jpeg'
7
+ # this would return 'test'
8
+ #
9
+ # === Returns
10
+ #
11
+ # [String] the first part of the filename
12
+ #
13
+ def basename
14
+ split_extension(filename)[0] if filename
15
+ end
16
+
17
+ ##
18
+ # Returns the file extension
19
+ #
20
+ # === Returns
21
+ #
22
+ # [String] extension of file or "" if the file has no extension
23
+ #
24
+ def extension
25
+ split_extension(filename)[1] if filename
26
+ end
27
+
28
+ private
29
+
30
+ def split_extension(filename)
31
+ # regular expressions to try for identifying extensions
32
+ extension_matchers = [
33
+ /\A(.+)\.(tar\.([glx]?z|bz2))\z/, # matches "something.tar.gz"
34
+ /\A(.+)\.([^\.]+)\z/ # matches "something.jpg"
35
+ ]
36
+
37
+ extension_matchers.each do |regexp|
38
+ if filename =~ regexp
39
+ return $1, $2
40
+ end
41
+ end
42
+
43
+ [filename, ""] # In case we weren't able to split the extension
44
+ end
45
+ end # FileName
46
+ end # Utilities
47
+ end # CarrierWave
@@ -3,20 +3,23 @@ require 'uri'
3
3
  module CarrierWave
4
4
  module Utilities
5
5
  module Uri
6
- # based on Ruby < 2.0's URI.encode
7
- SAFE_STRING = URI::REGEXP::PATTERN::UNRESERVED + '\/'
8
- UNSAFE = Regexp.new("[^#{SAFE_STRING}]", false)
6
+ # based on Ruby < 2.0's URI.encode
7
+ PATH_SAFE = URI::REGEXP::PATTERN::UNRESERVED + '\/'
8
+ PATH_UNSAFE = Regexp.new("[^#{PATH_SAFE}]", false)
9
+ NON_ASCII = /[^[:ascii:]]/.freeze
9
10
 
10
11
  private
12
+
11
13
  def encode_path(path)
12
- path.to_s.gsub(UNSAFE) do
13
- us = $&
14
- tmp = ''
15
- us.each_byte do |uc|
16
- tmp << sprintf('%%%02X', uc)
17
- end
18
- tmp
19
- end
14
+ URI::DEFAULT_PARSER.escape(path, PATH_UNSAFE)
15
+ end
16
+
17
+ def encode_non_ascii(str)
18
+ URI::DEFAULT_PARSER.escape(str, NON_ASCII)
19
+ end
20
+
21
+ def decode_uri(str)
22
+ URI::DEFAULT_PARSER.unescape(str)
20
23
  end
21
24
  end # Uri
22
25
  end # Utilities
@@ -1,4 +1,5 @@
1
1
  require 'carrierwave/utilities/uri'
2
+ require 'carrierwave/utilities/file_name'
2
3
 
3
4
  module CarrierWave
4
5
  module Utilities
@@ -11,9 +11,8 @@ module CarrierWave
11
11
  class ProcessingValidator < ::ActiveModel::EachValidator
12
12
 
13
13
  def validate_each(record, attribute, value)
14
- if e = record.__send__("#{attribute}_processing_error")
15
- message = (e.message == e.class.to_s) ? :carrierwave_processing_error : e.message
16
- record.errors.add(attribute, message)
14
+ record.__send__("#{attribute}_processing_errors").each do |e|
15
+ record.errors.add(attribute, :carrierwave_processing_error, message: (e.message != e.class.to_s) && e.message)
17
16
  end
18
17
  end
19
18
  end
@@ -21,9 +20,8 @@ module CarrierWave
21
20
  class IntegrityValidator < ::ActiveModel::EachValidator
22
21
 
23
22
  def validate_each(record, attribute, value)
24
- if e = record.__send__("#{attribute}_integrity_error")
25
- message = (e.message == e.class.to_s) ? :carrierwave_integrity_error : e.message
26
- record.errors.add(attribute, message)
23
+ record.__send__("#{attribute}_integrity_errors").each do |e|
24
+ record.errors.add(attribute, :carrierwave_integrity_error, message: (e.message != e.class.to_s) && e.message)
27
25
  end
28
26
  end
29
27
  end
@@ -31,9 +29,8 @@ module CarrierWave
31
29
  class DownloadValidator < ::ActiveModel::EachValidator
32
30
 
33
31
  def validate_each(record, attribute, value)
34
- if e = record.__send__("#{attribute}_download_error")
35
- message = (e.message == e.class.to_s) ? :carrierwave_download_error : e.message
36
- record.errors.add(attribute, message)
32
+ record.__send__("#{attribute}_download_errors").each do |e|
33
+ record.errors.add(attribute, :carrierwave_download_error, message: (e.message != e.class.to_s) && e.message)
37
34
  end
38
35
  end
39
36
  end
@@ -58,6 +55,7 @@ module CarrierWave
58
55
  def validates_processing_of(*attr_names)
59
56
  validates_with ProcessingValidator, _merge_attributes(attr_names)
60
57
  end
58
+
61
59
  #
62
60
  ##
63
61
  # Makes the record invalid if the remote file couldn't be downloaded
@@ -1,3 +1,3 @@
1
1
  module CarrierWave
2
- VERSION = "1.3.1"
2
+ VERSION = "3.0.5".freeze
3
3
  end