active_storage_validations 0.9.6 → 0.9.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 52bbd6249bbadd7549ccd7daf17673e98ccfd757b15ec954b67c5d7ce3395c84
4
- data.tar.gz: cf3664efb821cd7fe60b0536e0d394f900af6fb128161ab13d62d373b2018013
3
+ metadata.gz: 0f77bdb678731cdb6bb3aca1bddf3a3b1d1d4f34355a778c504931d067f6d0e2
4
+ data.tar.gz: cb723cb17a4cbfcfec2e7a9b8432ac0d2641afbef327a92e38baa376d15ba2fd
5
5
  SHA512:
6
- metadata.gz: bece2608d56156a83e468ffaf4ed31dead1769882457c1ff8480586ce0335122b475084f24f914d4d8083c5b4f2b891bda7465b25b2d34272ba76631c313167f
7
- data.tar.gz: 56a1cbb1bd5bddc4cce887405eecd6d5e27cc9bfcdca97e636ccf43cf98ce29d9077e1b3e7a602dcb229cd24d25125024c4d83beba6f82050edc773b32d21ca4
6
+ metadata.gz: d44aed46b1f790d3df1913009fc1c84ea5831be3c8809063c94a0c50de3d8b9f40613eab920c49fb8f81dd0808d9c489aebb1705e022defe1e745d1205a48203
7
+ data.tar.gz: 3d770860efb253f13ea1f18086c5b8a51253caf69875ba1d9d7921c17b9c5ce43f8001f4d8eeb1e095f8f37d1f0924dbddcdb35ca24b721d6fd5cf2a002d9a90
data/README.md CHANGED
@@ -26,16 +26,17 @@ For example you have a model like this and you want to add validation.
26
26
  class User < ApplicationRecord
27
27
  has_one_attached :avatar
28
28
  has_many_attached :photos
29
+ has_one_attached :image
29
30
 
30
31
  validates :name, presence: true
31
32
 
32
33
  validates :avatar, attached: true, content_type: 'image/png',
33
34
  dimension: { width: 200, height: 200 }
34
- validates :photos, attached: true, content_type: ['image/png', 'image/jpg', 'image/jpeg'],
35
+ validates :photos, attached: true, content_type: ['image/png', 'image/jpeg'],
35
36
  dimension: { width: { min: 800, max: 2400 },
36
37
  height: { min: 600, max: 1800 }, message: 'is not given between dimension' }
37
38
  validates :image, attached: true,
38
- content_type: ['image/png', 'image/jpg'],
39
+ content_type: ['image/png', 'image/jpeg'],
39
40
  aspect_ratio: :landscape
40
41
  end
41
42
  ```
@@ -44,13 +45,15 @@ or
44
45
 
45
46
  ```ruby
46
47
  class Project < ApplicationRecord
48
+ has_one_attached :logo
47
49
  has_one_attached :preview
48
50
  has_one_attached :attachment
49
51
  has_many_attached :documents
50
52
 
51
53
  validates :title, presence: true
52
54
 
53
- validates :preview, attached: true, size: { less_than: 100.megabytes , message: 'is not given between size' }
55
+ validates :logo, attached: true, size: { less_than: 100.megabytes , message: 'is too large' }
56
+ validates :preview, attached: true, size: { between: 1.kilobyte..100.megabytes , message: 'is not given between size' }
54
57
  validates :attachment, attached: true, content_type: { in: 'application/pdf', message: 'is not a PDF' }
55
58
  validates :documents, limit: { min: 1, max: 3 }
56
59
  end
@@ -177,6 +180,8 @@ gem 'active_storage_validations'
177
180
 
178
181
  # Optional, to use :dimension validator or :aspect_ratio validator
179
182
  gem 'mini_magick', '>= 4.9.5'
183
+ # Or
184
+ gem 'ruby-vips', '>= 2.1.0'
180
185
  ```
181
186
 
182
187
  And then execute:
@@ -301,10 +306,12 @@ Snippet to run in console:
301
306
  BUNDLE_GEMFILE=gemfiles/rails_5_2.gemfile bundle
302
307
  BUNDLE_GEMFILE=gemfiles/rails_6_0.gemfile bundle
303
308
  BUNDLE_GEMFILE=gemfiles/rails_6_1.gemfile bundle
309
+ BUNDLE_GEMFILE=gemfiles/rails_7_0.gemfile bundle
304
310
  BUNDLE_GEMFILE=gemfiles/rails_next.gemfile bundle
305
311
  BUNDLE_GEMFILE=gemfiles/rails_5_2.gemfile bundle exec rake test
306
312
  BUNDLE_GEMFILE=gemfiles/rails_6_0.gemfile bundle exec rake test
307
313
  BUNDLE_GEMFILE=gemfiles/rails_6_1.gemfile bundle exec rake test
314
+ BUNDLE_GEMFILE=gemfiles/rails_7_0.gemfile bundle exec rake test
308
315
  BUNDLE_GEMFILE=gemfiles/rails_next.gemfile bundle exec rake test
309
316
  ```
310
317
 
@@ -362,6 +369,12 @@ You are welcome to contribute.
362
369
  - https://github.com/vietqhoang
363
370
  - https://github.com/kemenaran
364
371
  - https://github.com/jrmhaig
372
+ - https://github.com/tagliala
373
+ - https://github.com/evedovelli
374
+ - https://github.com/JuanVqz
375
+ - https://github.com/luiseugenio
376
+ - https://github.com/equivalent
377
+ - https://github.com/NARKOZ
365
378
 
366
379
  ## License
367
380
 
@@ -2,21 +2,21 @@ pt-BR:
2
2
  errors:
3
3
  messages:
4
4
  content_type_invalid: "tem um tipo de arquivo inválido"
5
- file_size_out_of_range: "tamanho %{file_size} está fora da faixa de tamanho válida"
6
- limit_out_of_range: "número total está fora do limite"
5
+ file_size_out_of_range: "tem tamanho %{file_size} e está fora da faixa de tamanho válida"
6
+ limit_out_of_range: "o número total está fora do limite"
7
7
  image_metadata_missing: "não é uma imagem válida"
8
- dimension_min_inclusion: "deve ser maior ou igual a %{width} x %{height} pixel"
9
- dimension_max_inclusion: "deve ser menor ou igual a %{width} x %{height} pixel"
10
- dimension_width_inclusion: "largura não está entre %{min} e %{max} pixel"
11
- dimension_height_inclusion: "altura não está entre %{min} e %{max} pixel"
12
- dimension_width_greater_than_or_equal_to: "largura deve ser maior ou igual a %{length} pixel"
13
- dimension_height_greater_than_or_equal_to: "altura deve ser maior ou igual a %{length} pixel"
14
- dimension_width_less_than_or_equal_to: "largura deve ser menor ou igual a %{length} pixel"
15
- dimension_height_less_than_or_equal_to: "altura deve ser menor ou igual a %{length} pixel"
16
- dimension_width_equal_to: "largura deve ser igual a %{length} pixel"
17
- dimension_height_equal_to: "altura deve ser igual a %{length} pixel"
8
+ dimension_min_inclusion: "deve ser maior ou igual a %{width} x %{height} pixels"
9
+ dimension_max_inclusion: "deve ser menor ou igual a %{width} x %{height} pixels"
10
+ dimension_width_inclusion: "deve ter largura entre %{min} e %{max} pixels"
11
+ dimension_height_inclusion: "deve ter altura entre %{min} e %{max} pixels"
12
+ dimension_width_greater_than_or_equal_to: "deve ter largura maior ou igual a %{length} pixels"
13
+ dimension_height_greater_than_or_equal_to: "deve ter altura maior ou igual a %{length} pixels"
14
+ dimension_width_less_than_or_equal_to: "deve ter largura menor ou igual a %{length} pixels"
15
+ dimension_height_less_than_or_equal_to: "deve ter altura menor ou igual a %{length} pixels"
16
+ dimension_width_equal_to: "deve ter largura igual a %{length} pixels"
17
+ dimension_height_equal_to: "deve ter altura igual a %{length} pixels"
18
18
  aspect_ratio_not_square: "não é uma imagem quadrada"
19
- aspect_ratio_not_portrait: "não contém uma imagem no formato retrato"
20
- aspect_ratio_not_landscape: "não contém uma imagem no formato paisagem"
19
+ aspect_ratio_not_portrait: "não está no formato retrato"
20
+ aspect_ratio_not_landscape: "não está no formato paisagem"
21
21
  aspect_ratio_is_not: "não contém uma proporção de %{aspect_ratio}"
22
22
  aspect_ratio_unknown: "não tem uma proporção definida"
@@ -8,7 +8,6 @@ module ActiveStorageValidations
8
8
  PRECISION = 3
9
9
 
10
10
  def initialize(options)
11
- require 'mini_magick' unless defined?(MiniMagick)
12
11
  super(options)
13
12
  end
14
13
 
@@ -37,14 +36,14 @@ module ActiveStorageValidations
37
36
  # Rails 5
38
37
  def validate_each(record, attribute, _value)
39
38
  return true unless record.send(attribute).attached?
40
-
39
+
41
40
  files = Array.wrap(record.send(attribute))
42
-
41
+
43
42
  files.each do |file|
44
43
  # Analyze file first if not analyzed to get all required metadata.
45
44
  file.analyze; file.reload unless file.analyzed?
46
45
  metadata = file.metadata
47
-
46
+
48
47
  next if is_valid?(record, attribute, metadata)
49
48
  break
50
49
  end
@@ -7,8 +7,6 @@ module ActiveStorageValidations
7
7
  AVAILABLE_CHECKS = %i[width height min max].freeze
8
8
 
9
9
  def initialize(options)
10
- require 'mini_magick' unless defined?(MiniMagick)
11
-
12
10
  [:width, :height].each do |length|
13
11
  if options[length] and options[length].is_a?(Hash)
14
12
  if range = options[length][:in]
@@ -35,7 +35,7 @@ module ActiveStorageValidations
35
35
  def failure_message
36
36
  <<~MESSAGE
37
37
  Expected #{@attribute_name}
38
-
38
+
39
39
  Accept content types: #{allowed_types.join(", ")}
40
40
  #{accepted_types_and_failures}
41
41
 
@@ -57,7 +57,7 @@ module ActiveStorageValidations
57
57
  end
58
58
 
59
59
  def rejected_types
60
- @rejected_types || (Marcel::TYPES.keys - allowed_types)
60
+ @rejected_types || (content_type_keys - allowed_types)
61
61
  end
62
62
 
63
63
  def allowed_types_allowed?
@@ -96,6 +96,16 @@ module ActiveStorageValidations
96
96
  suffix = type.to_s.split('/').last
97
97
  { io: Tempfile.new('.'), filename: "test.#{suffix}", content_type: type }
98
98
  end
99
+
100
+ private
101
+
102
+ def content_type_keys
103
+ if Rails.gem_version < Gem::Version.new('6.1.0')
104
+ Mime::LOOKUP.keys
105
+ else
106
+ Marcel::TYPES.keys
107
+ end
108
+ end
99
109
  end
100
110
  end
101
111
  end
@@ -3,9 +3,22 @@ module ActiveStorageValidations
3
3
  attr_reader :file
4
4
 
5
5
  def initialize(file)
6
+ require_image_processor
6
7
  @file = file
7
8
  end
8
9
 
10
+ def image_processor
11
+ Rails.application.config.active_storage.variant_processor
12
+ end
13
+
14
+ def require_image_processor
15
+ if image_processor == :vips
16
+ require 'vips' unless defined?(Vips)
17
+ else
18
+ require 'mini_magick' unless defined?(MiniMagick)
19
+ end
20
+ end
21
+
9
22
  def metadata
10
23
  read_image do |image|
11
24
  if rotated_image?(image)
@@ -42,29 +55,53 @@ module ActiveStorageValidations
42
55
  tempfile.flush
43
56
  tempfile.rewind
44
57
 
45
- image = MiniMagick::Image.new(tempfile.path)
58
+ image = if image_processor == :vips && Vips::get_suffixes.include?(File.extname(tempfile.path))
59
+ Vips::Image.new_from_file(tempfile.path)
60
+ else
61
+ MiniMagick::Image.new(tempfile.path)
62
+ end
46
63
  else
47
- image = MiniMagick::Image.new(read_file_path)
64
+ image = if image_processor == :vips && Vips::get_suffixes.include?(File.extname(read_file_path))
65
+ Vips::Image.new_from_file(read_file_path)
66
+ else
67
+ MiniMagick::Image.new(read_file_path)
68
+ end
48
69
  end
49
70
 
50
- if image.valid?
71
+ if image && valid_image?(image)
51
72
  yield image
52
73
  else
53
- logger.info "Skipping image analysis because ImageMagick doesn't support the file"
74
+ logger.info "Skipping image analysis because ImageMagick or Vips doesn't support the file"
54
75
  {}
55
76
  end
56
- rescue LoadError
57
- logger.info "Skipping image analysis because the mini_magick gem isn't installed"
77
+ rescue LoadError, NameError
78
+ logger.info "Skipping image analysis because the mini_magick or ruby-vips gem isn't installed"
58
79
  {}
59
80
  rescue MiniMagick::Error => error
60
81
  logger.error "Skipping image analysis due to an ImageMagick error: #{error.message}"
61
82
  {}
83
+ rescue Vips::Error => error
84
+ logger.error "Skipping image analysis due to a Vips error: #{error.message}"
85
+ {}
62
86
  ensure
63
87
  image = nil
64
88
  end
65
89
 
90
+ def valid_image?(image)
91
+ image_processor == :vips ? image.avg : image.valid?
92
+ rescue Vips::Error
93
+ false
94
+ end
95
+
66
96
  def rotated_image?(image)
67
- %w[ RightTop LeftBottom ].include?(image["%[orientation]"])
97
+ if image_processor == :vips
98
+ image.get('exif-ifd0-Orientation').include?('Right-top') ||
99
+ image.get('exif-ifd0-Orientation').include?('Left-bottom')
100
+ else
101
+ %w[ RightTop LeftBottom ].include?(image["%[orientation]"])
102
+ end
103
+ rescue Vips::Error # field "exif-ifd0-Orientation" not found
104
+ false
68
105
  end
69
106
 
70
107
  def read_file_path
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveStorageValidations
4
- VERSION = '0.9.6'
4
+ VERSION = '0.9.7'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_storage_validations
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.6
4
+ version: 0.9.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Igor Kasyanchuk
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-11-23 00:00:00.000000000 Z
11
+ date: 2022-03-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activejob
@@ -94,6 +94,20 @@ dependencies:
94
94
  - - ">="
95
95
  - !ruby/object:Gem::Version
96
96
  version: 4.9.5
97
+ - !ruby/object:Gem::Dependency
98
+ name: ruby-vips
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: 2.1.0
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: 2.1.0
97
111
  - !ruby/object:Gem::Dependency
98
112
  name: pry
99
113
  requirement: !ruby/object:Gem::Requirement
@@ -136,6 +150,20 @@ dependencies:
136
150
  - - ">="
137
151
  - !ruby/object:Gem::Version
138
152
  version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: marcel
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
139
167
  description: Validations for Active Storage (presence)
140
168
  email:
141
169
  - igorkasyanchuk@gmail.com
@@ -180,7 +208,7 @@ homepage: https://github.com/igorkasyanchuk/active_storage_validations
180
208
  licenses:
181
209
  - MIT
182
210
  metadata: {}
183
- post_install_message:
211
+ post_install_message:
184
212
  rdoc_options: []
185
213
  require_paths:
186
214
  - lib
@@ -195,8 +223,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
195
223
  - !ruby/object:Gem::Version
196
224
  version: '0'
197
225
  requirements: []
198
- rubygems_version: 3.1.4
199
- signing_key:
226
+ rubygems_version: 3.2.3
227
+ signing_key:
200
228
  specification_version: 4
201
229
  summary: Validations for Active Storage
202
230
  test_files: []