active_storage_validations 0.9.6 → 0.9.7

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.
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: []