carrierwave 2.2.1 → 3.0.1

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 (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 +27 -13
  5. data/lib/carrierwave/downloader/remote_file.rb +12 -9
  6. data/lib/carrierwave/locale/en.yml +5 -3
  7. data/lib/carrierwave/mount.rb +31 -50
  8. data/lib/carrierwave/mounter.rb +115 -50
  9. data/lib/carrierwave/orm/activerecord.rb +14 -60
  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 +75 -67
  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 +42 -7
  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 +150 -132
  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/uploader_generator.rb +3 -3
  40. metadata +31 -43
  41. /data/lib/generators/templates/{uploader.rb → uploader.rb.erb} +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a16b1f5ad9e05370bb6ad6381f5d94b36d3233c3ddbbd4782b54d3a01fb6a747
4
- data.tar.gz: a5093ecbce4d1ee217c6b78b57f6c50d6ecad9cff0c3b865a22ebbbd196743aa
3
+ metadata.gz: 93ce71b0513b78b021bb85c121625135145ea8b78fc21bb64542e9114220d6cf
4
+ data.tar.gz: cfa74c58a128998a51b9d50d1f1f5d44ca95aeeb1847ff860fc9e55aedc33f61
5
5
  SHA512:
6
- metadata.gz: 561070ea4b8d2eb9b6e606e4eb465aa3c6ecf3c5664102b5de9ada7317adbc8c8c2561b68baed39acb656cdece7509455e359b3f5ef9cb0e0c85202458c9ac02
7
- data.tar.gz: 386f211d2fb219185543d330e84cbc7331ef8fe0f48992a9ef98f965e96dce2b7ec8731317951867bfc68bf7496c08211cc840003130cc20154dd4173b095d47
6
+ metadata.gz: 320adb08f7b9e280f43daa2663acd22bbe7bfc26a03461210a888e593136fd65c641f2aae3d332091ab4c59704cec6b9293864f85e7eb676ebebd06648c1b943
7
+ data.tar.gz: 140d651ba46ecda9e0e9209e01731e02782d3e4dc113e6e0b042faa64b3277aace8ac1f69a9f626bf0e083f4b60b5b9665612ae66b481c1f96b0ef074961d7cc
data/README.md CHANGED
@@ -10,7 +10,7 @@ It works well with Rack based web applications, such as Ruby on Rails.
10
10
 
11
11
  ## Information
12
12
 
13
- * RDoc documentation [available on RubyDoc.info](http://rubydoc.info/gems/carrierwave/frames)
13
+ * RDoc documentation [available on RubyDoc.info](https://rubydoc.info/gems/carrierwave)
14
14
  * Source code [available on GitHub](http://github.com/carrierwaveuploader/carrierwave)
15
15
  * More information, known limitations, and how-tos [available on the wiki](https://github.com/carrierwaveuploader/carrierwave/wiki)
16
16
 
@@ -30,13 +30,19 @@ $ gem install carrierwave
30
30
  In Rails, add it to your Gemfile:
31
31
 
32
32
  ```ruby
33
- gem 'carrierwave', '~> 2.0'
33
+ gem 'carrierwave', '~> 3.0'
34
34
  ```
35
35
 
36
36
  Finally, restart the server to apply the changes.
37
37
 
38
- As of version 2.0, CarrierWave requires Rails 5.0 or higher and Ruby 2.2
39
- or higher. If you're on Rails 4, you should use 1.x.
38
+ ## Upgrading from 2.x or earlier
39
+
40
+ CarrierWave 3.0 comes with a change in the way of handling the file extension on conversion. This results in following issues if you use `process convert: :format` to change the file format:
41
+
42
+ - If you have it on the uploader itself (not within a version), the file extension of the cached file will change. That means if you serve both CarrierWave 2.x and 3.x simultaneously on the same workload (e.g. using blue-green deployment), a cache file stored by 2.x can't be retrieved by 3.x and vice versa.
43
+ - If you have it within a version, the file extension of the stored file will change. You need to perform `#recreate_versions!` to make it usable again.
44
+
45
+ To preserve the 2.x behavior, you can set `force_extension false` right after calling `process convert: :format`. See [#2659](https://github.com/carrierwaveuploader/carrierwave/pull/2659) for the detail.
40
46
 
41
47
  ## Getting Started
42
48
 
@@ -227,6 +233,20 @@ class MyUploader < CarrierWave::Uploader::Base
227
233
  end
228
234
  ```
229
235
 
236
+ ## Changing the filename
237
+
238
+ To change the filename of uploaded files, you can override `#filename` method in the uploader.
239
+
240
+ ```ruby
241
+ class MyUploader < CarrierWave::Uploader::Base
242
+ def filename
243
+ "image.#{file.extension}" # If you upload 'file.jpg', you'll get 'image.jpg'
244
+ end
245
+ end
246
+ ```
247
+
248
+ Some old documentations (like [this](https://stackoverflow.com/a/5865117)) may instruct you to safeguard the filename value with `if original_filename`, but it's no longer necessary with CarrierWave 3.0 or later.
249
+
230
250
  ## Securing uploads
231
251
 
232
252
  Certain files might be dangerous if uploaded to the wrong location, such as PHP
@@ -305,17 +325,8 @@ You no longer need to do this manually.
305
325
 
306
326
  ## Adding versions
307
327
 
308
- Often you'll want to add different versions of the same file. The classic example is image thumbnails. There is built in support for this*:
309
-
310
- *Note:* You must have Imagemagick installed to do image resizing.
311
-
312
- Some documentation refers to RMagick instead of MiniMagick but MiniMagick is recommended.
313
-
314
- To install Imagemagick on OSX with homebrew type the following:
315
-
316
- ```
317
- $ brew install imagemagick
318
- ```
328
+ Often you'll want to add different versions of the same file. The classic example is generating image thumbnails while preserving the original file to be used for high-quality representation.
329
+ In this section we'll explore how CarrierWave supports working with multiple versions. The image manipulation itself is covered in [another section](#manipulating-images).
319
330
 
320
331
  ```ruby
321
332
  class MyUploader < CarrierWave::Uploader::Base
@@ -351,17 +362,7 @@ uploader.thumb.url # => '/url/to/thumb_my_file.png' # size: 200x200
351
362
  One important thing to remember is that process is called *before* versions are
352
363
  created. This can cut down on processing cost.
353
364
 
354
- ### Processing Methods: mini_magick
355
-
356
- - `convert` - Changes the image encoding format to the given format, eg. jpg
357
- - `resize_to_limit` - Resize the image to fit within the specified dimensions while retaining the original aspect ratio. Will only resize the image if it is larger than the specified dimensions. The resulting image may be shorter or narrower than specified in the smaller dimension but will not be larger than the specified values.
358
- - `resize_to_fit` - Resize the image to fit within the specified dimensions while retaining the original aspect ratio. The image may be shorter or narrower than specified in the smaller dimension but will not be larger than the specified values.
359
- - `resize_to_fill` - Resize the image to fit within the specified dimensions while retaining the aspect ratio of the original image. If necessary, crop the image in the larger dimension. Optionally, a "gravity" may be specified, for example "Center", or "NorthEast".
360
- - `resize_and_pad` - Resize the image to fit within the specified dimensions while retaining the original aspect ratio. If necessary, will pad the remaining area with the given color, which defaults to transparent (for gif and png, white for jpeg). Optionally, a "gravity" may be specified, as above.
361
-
362
- See `carrierwave/processing/mini_magick.rb` for details.
363
-
364
- ### conditional process
365
+ ### Conditional processing
365
366
 
366
367
  If you want to use conditional process, you can only use `if` statement.
367
368
 
@@ -445,8 +446,27 @@ class MyUploader < CarrierWave::Uploader::Base
445
446
  end
446
447
  ```
447
448
 
448
- The option `:from_version` uses the file cached in the `:thumb` version instead
449
- of the original version, potentially resulting in faster processing.
449
+ ### Customizing version filenames
450
+
451
+ CarrierWave supports [customization of filename](#changing-the-filename) by overriding an uploader's
452
+ #filename method, but this doesn't work for versions because of the limitation on how CarrierWave
453
+ re-constructs the filename on retrieval of the stored file.
454
+ Instead, you can override `#full_filename` with providing a version-aware name.
455
+
456
+ ```ruby
457
+ class MyUploader < CarrierWave::Uploader::Base
458
+ version :thumb do
459
+ def full_filename(for_file)
460
+ 'thumb.png'
461
+ end
462
+ process convert: 'png'
463
+ end
464
+ end
465
+ ```
466
+
467
+ Please note that `#full_filename` mustn't be constructed based on a dynamic value
468
+ that can change from the time of store and time of retrieval, since it will result in
469
+ being unable to retrieve a file previously stored.
450
470
 
451
471
  ## Making uploads work across form redisplays
452
472
 
@@ -531,6 +551,17 @@ failures automatically with attribute validation errors. If you aren't, or you
531
551
  disable CarrierWave's `validate_download` option, you'll need to handle those
532
552
  errors yourself.
533
553
 
554
+ ### Retry option for download from remote location
555
+ If you want to retry the download from the Remote URL, enable the download_retry_count option, an error occurs during download, it will try to execute the specified number of times.
556
+ This option is effective when the remote destination is unstable.
557
+
558
+ ```rb
559
+ CarrierWave.configure do |config|
560
+ config.download_retry_count = 3 # Default 0
561
+ config.download_retry_wait_time = 3 # Default 5
562
+ end
563
+ ```
564
+
534
565
  ## Providing a default URL
535
566
 
536
567
  In many cases, especially when working with images, it might be a good idea to
@@ -832,7 +863,6 @@ Please read the [fog-google README](https://github.com/fog/fog-google/blob/maste
832
863
  For Google Storage JSON API (recommended):
833
864
  ```ruby
834
865
  CarrierWave.configure do |config|
835
- config.fog_provider = 'fog/google'
836
866
  config.fog_credentials = {
837
867
  provider: 'Google',
838
868
  google_project: 'my-project',
@@ -846,7 +876,6 @@ end
846
876
  For Google Storage XML API:
847
877
  ```ruby
848
878
  CarrierWave.configure do |config|
849
- config.fog_provider = 'fog/google'
850
879
  config.fog_credentials = {
851
880
  provider: 'Google',
852
881
  google_storage_access_key_id: 'xxxxxx',
@@ -905,67 +934,81 @@ CarrierWave.configure do |config|
905
934
  end
906
935
  ```
907
936
 
908
- ## Using RMagick
937
+ ## Manipulating images
909
938
 
910
939
  If you're uploading images, you'll probably want to manipulate them in some way,
911
- you might want to create thumbnail images for example. CarrierWave comes with a
912
- small library to make manipulating images with RMagick easier, you'll need to
913
- include it in your Uploader:
940
+ you might want to create thumbnail images for example.
914
941
 
915
- ```ruby
916
- class AvatarUploader < CarrierWave::Uploader::Base
917
- include CarrierWave::RMagick
918
- end
942
+ ### Using MiniMagick
943
+
944
+ MiniMagick performs all the operations using the 'convert' CLI which is part of the standard ImageMagick kit.
945
+ This allows you to have the power of ImageMagick without having to worry about installing
946
+ all the RMagick libraries, it often results in higher memory footprint.
947
+
948
+ See the MiniMagick site for more details:
949
+
950
+ https://github.com/minimagick/minimagick
951
+
952
+ To install Imagemagick on OSX with homebrew type the following:
953
+
954
+ ```
955
+ $ brew install imagemagick
919
956
  ```
920
957
 
921
- The RMagick module gives you a few methods, like
922
- `CarrierWave::RMagick#resize_to_fill` which manipulate the image file in some
923
- way. You can set a `process` callback, which will call that method any time a
924
- file is uploaded.
925
- There is a demonstration of convert here.
926
- Convert will only work if the file has the same file extension, thus the use of the filename method.
958
+ And the ImageMagick command line options for more for what's on offer:
959
+
960
+ http://www.imagemagick.org/script/command-line-options.php
961
+
962
+ Currently, the MiniMagick carrierwave processor provides exactly the same methods as
963
+ for the RMagick processor.
927
964
 
928
965
  ```ruby
929
966
  class AvatarUploader < CarrierWave::Uploader::Base
930
- include CarrierWave::RMagick
967
+ include CarrierWave::MiniMagick
931
968
 
932
969
  process resize_to_fill: [200, 200]
933
- process convert: 'png'
934
-
935
- def filename
936
- super.chomp(File.extname(super)) + '.png' if original_filename.present?
937
- end
938
970
  end
939
971
  ```
940
972
 
941
- Check out the manipulate! method, which makes it easy for you to write your own
942
- manipulation methods.
973
+ #### List of available processing methods:
943
974
 
944
- ## Using MiniMagick
945
-
946
- MiniMagick is similar to RMagick but performs all the operations using the 'convert'
947
- CLI which is part of the standard ImageMagick kit. This allows you to have the power
948
- of ImageMagick without having to worry about installing all the RMagick libraries.
975
+ - `convert` - Changes the image encoding format to the given format(eg. jpg). This operation is treated specially to trigger the change of the file extension, so it matches with the format of the resulting file.
976
+ - `resize_to_limit` - Resize the image to fit within the specified dimensions while retaining the original aspect ratio. Will only resize the image if it is larger than the specified dimensions. The resulting image may be shorter or narrower than specified in the smaller dimension but will not be larger than the specified values.
977
+ - `resize_to_fit` - Resize the image to fit within the specified dimensions while retaining the original aspect ratio. The image may be shorter or narrower than specified in the smaller dimension but will not be larger than the specified values.
978
+ - `resize_to_fill` - Resize the image to fit within the specified dimensions while retaining the aspect ratio of the original image. If necessary, crop the image in the larger dimension. Optionally, a "gravity" may be specified, for example "Center", or "NorthEast".
979
+ - `resize_and_pad` - Resize the image to fit within the specified dimensions while retaining the original aspect ratio. If necessary, will pad the remaining area with the given color, which defaults to transparent (for gif and png, white for jpeg). Optionally, a "gravity" may be specified, as above.
949
980
 
950
- See the MiniMagick site for more details:
981
+ See `carrierwave/processing/mini_magick.rb` for details.
951
982
 
952
- https://github.com/minimagick/minimagick
983
+ ### Using RMagick
953
984
 
954
- And the ImageMagick command line options for more for whats on offer:
985
+ CarrierWave also comes with support for RMagick, a well-known image processing library.
986
+ To use it, you'll need to include this in your Uploader:
955
987
 
956
- http://www.imagemagick.org/script/command-line-options.php
988
+ ```ruby
989
+ class AvatarUploader < CarrierWave::Uploader::Base
990
+ include CarrierWave::RMagick
991
+ end
992
+ ```
957
993
 
958
- Currently, the MiniMagick carrierwave processor provides exactly the same methods as
959
- for the RMagick processor.
994
+ The RMagick module gives you a few methods, like
995
+ `CarrierWave::RMagick#resize_to_fill` which manipulate the image file in some
996
+ way. You can set a `process` callback, which will call that method any time a
997
+ file is uploaded.
998
+ There is a demonstration of convert here.
960
999
 
961
1000
  ```ruby
962
1001
  class AvatarUploader < CarrierWave::Uploader::Base
963
- include CarrierWave::MiniMagick
1002
+ include CarrierWave::RMagick
964
1003
 
965
1004
  process resize_to_fill: [200, 200]
1005
+ process convert: 'png'
966
1006
  end
967
1007
  ```
968
1008
 
1009
+ Check out the manipulate! method, which makes it easy for you to write your own
1010
+ manipulation methods.
1011
+
969
1012
  ## Migrating from Paperclip
970
1013
 
971
1014
  If you are using Paperclip, you can use the provided compatibility module:
@@ -1000,10 +1043,13 @@ errors:
1000
1043
  extension_denylist_error: "You are not allowed to upload %{extension} files, prohibited types: %{prohibited_types}"
1001
1044
  content_type_allowlist_error: "You are not allowed to upload %{content_type} files, allowed types: %{allowed_types}"
1002
1045
  content_type_denylist_error: "You are not allowed to upload %{content_type} files"
1003
- rmagick_processing_error: "Failed to manipulate with rmagick, maybe it is not an image?"
1004
- mini_magick_processing_error: "Failed to manipulate with MiniMagick, maybe it is not an image? Original Error: %{e}"
1046
+ processing_error: "Failed to manipulate, maybe it is not an image?"
1005
1047
  min_size_error: "File size should be greater than %{min_size}"
1006
1048
  max_size_error: "File size should be less than %{max_size}"
1049
+ min_width_error: "Image width should be greater than %{min_width}px"
1050
+ max_width_error: "Image width should be less than %{max_width}px"
1051
+ min_height_error: "Image height should be greater than %{min_height}px"
1052
+ max_height_error: "Image height should be less than %{max_height}px"
1007
1053
  ```
1008
1054
 
1009
1055
  The [`carrierwave-i18n`](https://github.com/carrierwaveuploader/carrierwave-i18n)
@@ -1066,6 +1112,30 @@ class User
1066
1112
  end
1067
1113
  ```
1068
1114
 
1115
+ ## Uploader Callbacks
1116
+
1117
+ In addition to the ActiveRecord callbacks described above, uploaders also have callbacks.
1118
+
1119
+ ```ruby
1120
+ class MyUploader < ::CarrierWave::Uploader::Base
1121
+ before :remove, :log_removal
1122
+ private
1123
+ def log_removal
1124
+ ::Rails.logger.info(format('Deleting file on S3: %s', @file))
1125
+ end
1126
+ end
1127
+ ```
1128
+
1129
+ Uploader callbacks can be `before` or `after` the following events:
1130
+
1131
+ ```
1132
+ cache
1133
+ process
1134
+ remove
1135
+ retrieve_from_cache
1136
+ store
1137
+ ```
1138
+
1069
1139
  ## Contributing to CarrierWave
1070
1140
 
1071
1141
  See [CONTRIBUTING.md](https://github.com/carrierwaveuploader/carrierwave/blob/master/CONTRIBUTING.md)
@@ -1074,7 +1144,7 @@ See [CONTRIBUTING.md](https://github.com/carrierwaveuploader/carrierwave/blob/ma
1074
1144
 
1075
1145
  The MIT License (MIT)
1076
1146
 
1077
- Copyright (c) 2008-2015 Jonas Nicklas
1147
+ Copyright (c) 2008 Jonas Nicklas
1078
1148
 
1079
1149
  Permission is hereby granted, free of charge, to any person obtaining
1080
1150
  a copy of this software and associated documentation files (the
@@ -56,10 +56,11 @@ module CarrierWave
56
56
  :basename => lambda{|u, f| u.filename.gsub(/#{File.extname(u.filename)}$/, "") },
57
57
  :extension => lambda{|u, d| File.extname(u.filename).gsub(/^\.+/, "")},
58
58
  :class => lambda{|u, f| u.model.class.name.underscore.pluralize}
59
- }
59
+ }.freeze
60
60
 
61
61
  included do
62
62
  attr_accessor :filename
63
+
63
64
  class_attribute :mappings
64
65
  self.mappings ||= DEFAULT_MAPPINGS.dup
65
66
  end
@@ -92,7 +93,8 @@ module CarrierWave
92
93
  end
93
94
  end
94
95
 
95
- private
96
+ private
97
+
96
98
  def interpolate_paperclip_path(path)
97
99
  mappings.each_pair.inject(path) do |agg, pair|
98
100
  agg.gsub(":#{pair[0]}") { pair[1].call(self, self.paperclip_style).to_s }
@@ -6,6 +6,8 @@ require 'carrierwave/downloader/remote_file'
6
6
  module CarrierWave
7
7
  module Downloader
8
8
  class Base
9
+ include CarrierWave::Utilities::Uri
10
+
9
11
  attr_reader :uploader
10
12
 
11
13
  def initialize(uploader)
@@ -21,6 +23,7 @@ module CarrierWave
21
23
  # [remote_headers (Hash)] Request headers
22
24
  #
23
25
  def download(url, remote_headers = {})
26
+ @current_download_retry_count = 0
24
27
  headers = remote_headers.
25
28
  reverse_merge('User-Agent' => "CarrierWave/#{CarrierWave::VERSION}")
26
29
  uri = process_uri(url.to_s)
@@ -29,14 +32,26 @@ module CarrierWave
29
32
  response = OpenURI.open_uri(process_uri(url.to_s), headers)
30
33
  else
31
34
  request = nil
32
- response = SsrfFilter.get(uri, headers: headers) do |req|
33
- request = req
35
+ if ::SsrfFilter::VERSION.to_f < 1.1
36
+ response = SsrfFilter.get(uri, headers: headers) do |req|
37
+ request = req
38
+ end
39
+ else
40
+ response = SsrfFilter.get(uri, headers: headers, request_proc: ->(req) { request = req }) do |res|
41
+ res.body # ensure to read body
42
+ end
34
43
  end
35
44
  response.uri = request.uri
36
45
  response.value
37
46
  end
38
47
  rescue StandardError => e
39
- raise CarrierWave::DownloadError, "could not download file: #{e.message}"
48
+ if @current_download_retry_count < @uploader.download_retry_count
49
+ @current_download_retry_count += 1
50
+ sleep @uploader.download_retry_wait_time
51
+ retry
52
+ else
53
+ raise CarrierWave::DownloadError, "could not download file: #{e.message}"
54
+ end
40
55
  end
41
56
  CarrierWave::Downloader::RemoteFile.new(response)
42
57
  end
@@ -48,17 +63,16 @@ module CarrierWave
48
63
  #
49
64
  # [url (String)] The URL where the remote file is stored
50
65
  #
51
- def process_uri(uri)
52
- uri_parts = uri.split('?')
53
- encoded_uri = Addressable::URI.parse(uri_parts.shift).normalize.to_s
54
- query = uri_parts.any? ? "?#{uri_parts.join('?')}" : ''
55
- begin
56
- URI.parse("#{encoded_uri}#{query}")
57
- rescue URI::InvalidURIError
58
- URI.parse("#{encoded_uri}#{URI::DEFAULT_PARSER.escape(query)}")
59
- end
66
+ def process_uri(source)
67
+ uri = Addressable::URI.parse(source)
68
+ uri.host = uri.normalized_host
69
+ # Perform decode first, as the path is likely to be already encoded
70
+ uri.path = encode_path(decode_uri(uri.path)) if uri.path =~ CarrierWave::Utilities::Uri::PATH_UNSAFE
71
+ uri.query = encode_non_ascii(uri.query) if uri.query
72
+ uri.fragment = encode_non_ascii(uri.fragment) if uri.fragment
73
+ URI.parse(uri.to_s)
60
74
  rescue URI::InvalidURIError, Addressable::URI::InvalidURIError
61
- raise CarrierWave::DownloadError, "couldn't parse URL: #{uri}"
75
+ raise CarrierWave::DownloadError, "couldn't parse URL: #{source}"
62
76
  end
63
77
 
64
78
  ##
@@ -8,7 +8,10 @@ module CarrierWave
8
8
  when String
9
9
  @file = StringIO.new(file)
10
10
  when Net::HTTPResponse
11
- @file = StringIO.new(file.body)
11
+ body = file.body
12
+ raise CarrierWave::DownloadError, 'could not download file: No Content' if body.nil?
13
+
14
+ @file = StringIO.new(body)
12
15
  @content_type = file.content_type
13
16
  @headers = file
14
17
  @uri = file.uri
@@ -30,18 +33,15 @@ module CarrierWave
30
33
 
31
34
  def original_filename
32
35
  filename = filename_from_header || filename_from_uri
33
- mime_type = MiniMime.lookup_by_content_type(content_type)
36
+ mime_type = Marcel::TYPES[content_type]
34
37
  unless File.extname(filename).present? || mime_type.blank?
35
- filename = "#{filename}.#{mime_type.extension}"
38
+ extension = mime_type[0].first
39
+ filename = "#{filename}.#{extension}"
36
40
  end
37
41
  filename
38
42
  end
39
43
 
40
- def respond_to?(*args)
41
- super || file.respond_to?(*args)
42
- end
43
-
44
- private
44
+ private
45
45
 
46
46
  def filename_from_header
47
47
  return nil unless headers['content-disposition']
@@ -59,7 +59,10 @@ module CarrierWave
59
59
  def method_missing(*args, &block)
60
60
  file.send(*args, &block)
61
61
  end
62
+
63
+ def respond_to_missing?(*args)
64
+ super || file.respond_to?(*args)
65
+ end
62
66
  end
63
67
  end
64
68
  end
65
-
@@ -8,8 +8,10 @@ en:
8
8
  extension_denylist_error: "You are not allowed to upload %{extension} files, prohibited types: %{prohibited_types}"
9
9
  content_type_allowlist_error: "You are not allowed to upload %{content_type} files, allowed types: %{allowed_types}"
10
10
  content_type_denylist_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?"
12
- mini_magick_processing_error: "Failed to manipulate with MiniMagick, maybe it is not an image? Original Error: %{e}"
13
- vips_processing_error: "Failed to manipulate with vips, maybe it is not an image? Original Error: %{e}"
11
+ processing_error: "Failed to manipulate, maybe it is not an image?"
14
12
  min_size_error: "File size should be greater than %{min_size}"
15
13
  max_size_error: "File size should be less than %{max_size}"
14
+ min_width_error: "Image width should be greater than %{min_width}px"
15
+ max_width_error: "Image width should be less than %{max_width}px"
16
+ min_height_error: "Image height should be greater than %{min_height}px"
17
+ max_height_error: "Image height should be less than %{max_height}px"
@@ -132,7 +132,7 @@ module CarrierWave
132
132
  # end
133
133
  #
134
134
  def mount_uploader(column, uploader=nil, options={}, &block)
135
- mount_base(column, uploader, options, &block)
135
+ mount_base(column, uploader, options.merge(multiple: false), &block)
136
136
 
137
137
  mod = Module.new
138
138
  include mod
@@ -163,21 +163,13 @@ module CarrierWave
163
163
  end
164
164
 
165
165
  def remote_#{column}_url=(url)
166
- _mounter(:#{column}).remote_urls = [url]
166
+ _mounter(:#{column}).remote_urls = url
167
167
  end
168
168
 
169
169
  def remote_#{column}_request_header=(header)
170
170
  _mounter(:#{column}).remote_request_headers = [header]
171
171
  end
172
172
 
173
- def write_#{column}_identifier
174
- return if frozen?
175
- mounter = _mounter(:#{column})
176
-
177
- mounter.clear! if mounter.remove?
178
- write_uploader(mounter.serialization_column, mounter.identifiers.first)
179
- end
180
-
181
173
  def #{column}_identifier
182
174
  _mounter(:#{column}).read_identifiers[0]
183
175
  end
@@ -193,16 +185,6 @@ module CarrierWave
193
185
  def #{column}_download_error
194
186
  #{column}_download_errors.last
195
187
  end
196
-
197
- def store_previous_changes_for_#{column}
198
- attribute_changes = ::ActiveRecord.version.to_s.to_f >= 5.1 ? saved_changes : changes
199
- @_previous_changes_for_#{column} = attribute_changes[_mounter(:#{column}).serialization_column]
200
- end
201
-
202
- def remove_previously_stored_#{column}
203
- before, after = @_previous_changes_for_#{column}
204
- _mounter(:#{column}).remove_previous([before], [after])
205
- end
206
188
  RUBY
207
189
  end
208
190
 
@@ -295,7 +277,7 @@ module CarrierWave
295
277
  # end
296
278
  #
297
279
  def mount_uploaders(column, uploader=nil, options={}, &block)
298
- mount_base(column, uploader, options, &block)
280
+ mount_base(column, uploader, options.merge(multiple: true), &block)
299
281
 
300
282
  mod = Module.new
301
283
  include mod
@@ -334,35 +316,18 @@ module CarrierWave
334
316
  _mounter(:#{column}).remote_request_headers = headers
335
317
  end
336
318
 
337
- def write_#{column}_identifier
338
- return if frozen?
339
- mounter = _mounter(:#{column})
340
-
341
- mounter.clear! if mounter.remove?
342
- write_uploader(mounter.serialization_column, mounter.identifiers.presence)
343
- end
344
-
345
319
  def #{column}_identifiers
346
320
  _mounter(:#{column}).read_identifiers
347
321
  end
348
-
349
- def store_previous_changes_for_#{column}
350
- attribute_changes = ::ActiveRecord.version.to_s.to_f >= 5.1 ? saved_changes : changes
351
- @_previous_changes_for_#{column} = attribute_changes[_mounter(:#{column}).serialization_column]
352
- end
353
-
354
- def remove_previously_stored_#{column}
355
- _mounter(:#{column}).remove_previous(*@_previous_changes_for_#{column})
356
- end
357
322
  RUBY
358
323
  end
359
324
 
360
- private
325
+ private
361
326
 
362
327
  def mount_base(column, uploader=nil, options={}, &block)
363
328
  include CarrierWave::Mount::Extension
364
329
 
365
- uploader = build_uploader(uploader, &block)
330
+ uploader = build_uploader(uploader, column, &block)
366
331
  uploaders[column.to_sym] = uploader
367
332
  uploader_options[column.to_sym] = options
368
333
 
@@ -387,6 +352,8 @@ module CarrierWave
387
352
 
388
353
  def remove_#{column}!
389
354
  _mounter(:#{column}).remove!
355
+ self.remove_#{column} = true
356
+ write_#{column}_identifier
390
357
  end
391
358
 
392
359
  def remove_#{column}=(value)
@@ -413,22 +380,36 @@ module CarrierWave
413
380
  _mounter(:#{column}).download_errors
414
381
  end
415
382
 
383
+ def write_#{column}_identifier
384
+ _mounter(:#{column}).write_identifier
385
+ end
386
+
416
387
  def mark_remove_#{column}_false
417
388
  _mounter(:#{column}).remove = false
418
389
  end
390
+
391
+ def reset_previous_changes_for_#{column}
392
+ _mounter(:#{column}).reset_changes!
393
+ end
394
+
395
+ def remove_previously_stored_#{column}
396
+ _mounter(:#{column}).remove_previous
397
+ end
398
+
399
+ def remove_rolled_back_#{column}
400
+ _mounter(:#{column}).remove_added
401
+ end
419
402
  RUBY
420
403
  end
421
404
 
422
- def build_uploader(uploader, &block)
423
- return uploader if uploader && !block_given?
405
+ def build_uploader(uploader, column, &block)
406
+ uploader ||= CarrierWave::Uploader::Base
407
+ return uploader unless block_given?
424
408
 
425
- uploader = Class.new(uploader || CarrierWave::Uploader::Base)
426
- const_set("Uploader#{uploader.object_id}".tr('-', '_'), uploader)
409
+ uploader = Class.new(uploader)
410
+ const_set("CarrierWave#{column.to_s.camelize}Uploader", uploader)
427
411
 
428
- if block_given?
429
- uploader.class_eval(&block)
430
- uploader.recursively_apply_block_to_versions(&block)
431
- end
412
+ uploader.class_eval(&block)
432
413
 
433
414
  uploader
434
415
  end
@@ -449,9 +430,9 @@ module CarrierWave
449
430
 
450
431
  def _mounter(column)
451
432
  # We cannot memoize in frozen objects :(
452
- return Mounter.new(self, column) if frozen?
433
+ return Mounter.build(self, column) if frozen?
453
434
  @_mounters ||= {}
454
- @_mounters[column] ||= Mounter.new(self, column)
435
+ @_mounters[column] ||= Mounter.build(self, column)
455
436
  end
456
437
 
457
438
  end # Extension