active_storage_validations 0.8.9 → 0.9.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 56d4f3fe66fc5eeb5ba573218aa39cea1bf41a2a579795f3a52d904cd02a0e99
4
- data.tar.gz: f8a7a311d1ea36080cfe20e9ffda3891720d0c2cf997aaa8d9bb272917137e8b
3
+ metadata.gz: 58ef7bbaa01aafa835921f0ad446b86e5b5c49a73a6f08e42feb97ff9bd3c7fd
4
+ data.tar.gz: e4f18d0de97ffa2adfe59e2d5d841706a8de3e6e575390aafb5b75dbf82a37a2
5
5
  SHA512:
6
- metadata.gz: 99f3f5c47db60e580e7d7d30ed44082871258ac7a64b6dd300ff8cb5d1b6f3272e03e0f4448e4ed994604909ff87ef38fc41711f5e2f09ddf4706a5ff79f1721
7
- data.tar.gz: d264bd552bad53dc5487eeb80235187da2c5d1f6b395621510f128753fbb5e832d6a3caa6819fa4f72c244898509163519309671803063e0b88b050607f73809
6
+ metadata.gz: 5b29620eb2a65e73c9f7c1c9d2bf143ba20aed0e460fdd763d415651b80463821f5dea26d2b28834dae7dc90ad035d6bbaa47bc7e89161365bfb154485a12c8b
7
+ data.tar.gz: ee7ef332175aca338df8d46de13ac0487f1aa4b5a3d7aa220bd14826b0f73f55377a6475c2b2eb9133d06aae456a2d18bdc4fbec07b7caaf9cd9fa3b8f1dcf5b
data/README.md CHANGED
@@ -1,10 +1,12 @@
1
1
  # Active Storage Validations
2
2
 
3
- If you are using `active_storage` gem and you want to add simple validations for it, like presence or content_type you need to write a custom valiation method.
3
+ [![MiniTest](https://github.com/igorkasyanchuk/active_storage_validations/workflows/MiniTest/badge.svg)](https://github.com/igorkasyanchuk/active_storage_validations/actions)
4
+ [![RailsJazz](https://github.com/igorkasyanchuk/rails_time_travel/blob/main/docs/my_other.svg?raw=true)](https://www.railsjazz.com)
5
+ [![https://www.patreon.com/igorkasyanchuk](https://github.com/igorkasyanchuk/rails_time_travel/blob/main/docs/patron.svg?raw=true)](https://www.patreon.com/igorkasyanchuk)
4
6
 
5
- This gems doing it for you. Just use `attached: true` or `content_type: 'image/png'` validation.
7
+ If you are using `active_storage` gem and you want to add simple validations for it, like presence or content_type you need to write a custom validation method.
6
8
 
7
- [![Build Status](https://travis-ci.org/igorkasyanchuk/active_storage_validations.svg?branch=master)](https://travis-ci.org/igorkasyanchuk/active_storage_validations)
9
+ This gems doing it for you. Just use `attached: true` or `content_type: 'image/png'` validation.
8
10
 
9
11
  ## What it can do
10
12
 
@@ -218,6 +220,7 @@ describe User do
218
220
 
219
221
  it { is_expected.to validate_dimensions_of(:avatar).width(250) }
220
222
  it { is_expected.to validate_dimensions_of(:avatar).height(200) }
223
+ it { is_expected.to validate_dimensions_of(:avatar).width(250).height(200).with_message('Invalid dimensions.') }
221
224
  it { is_expected.to validate_dimensions_of(:avatar).width_min(200) }
222
225
  it { is_expected.to validate_dimensions_of(:avatar).width_max(500) }
223
226
  it { is_expected.to validate_dimensions_of(:avatar).height_min(100) }
@@ -259,6 +262,7 @@ class UserTest < ActiveSupport::TestCase
259
262
 
260
263
  should validate_dimensions_of(:avatar).width(250)
261
264
  should validate_dimensions_of(:avatar).height(200)
265
+ should validate_dimensions_of(:avatar).width(250).height(200).with_message('Invalid dimensions.')
262
266
  should validate_dimensions_of(:avatar).width_min(200)
263
267
  should validate_dimensions_of(:avatar).width_max(500)
264
268
  should validate_dimensions_of(:avatar).height_min(100)
@@ -287,8 +291,7 @@ To run tests in root folder of gem:
287
291
 
288
292
  * `BUNDLE_GEMFILE=gemfiles/rails_5_2.gemfile bundle exec rake test` to run for Rails 5.2
289
293
  * `BUNDLE_GEMFILE=gemfiles/rails_6_0.gemfile bundle exec rake test` to run for Rails 6.0
290
-
291
- To play with app `cd test/dummy` and `rails s -b 0.0.0.0` (before `rails db:migrate`).
294
+ * `BUNDLE_GEMFILE=gemfiles/rails_6_1.gemfile bundle exec rake test` to run for Rails 6.1
292
295
 
293
296
  ## Known issues
294
297
 
@@ -330,7 +333,21 @@ You are welcome to contribute.
330
333
  - https://github.com/mohanklein
331
334
  - https://github.com/High5Apps
332
335
  - https://github.com/mschnitzer
336
+ - https://github.com/sinankeskin
337
+ - https://github.com/alejandrodevs
338
+ - https://github.com/molfar
339
+ - https://github.com/connorshea
340
+ - https://github.com/yshmarov
341
+ - https://github.com/fongfan999
342
+ - https://github.com/cooperka
343
+ - https://github.com/dolarsrg
344
+ - https://github.com/jayshepherd
345
+ - https://github.com/ohbarye
346
+ - https://github.com/...
333
347
 
334
348
  ## License
335
349
 
336
350
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
351
+
352
+ [<img src="https://github.com/igorkasyanchuk/rails_time_travel/blob/main/docs/more_gems.png?raw=true"
353
+ />](https://www.railsjazz.com/)
@@ -15,3 +15,8 @@ de:
15
15
  dimension_height_less_than_or_equal_to: "Höhe muss kleiner oder gleich %{length} Pixel sein"
16
16
  dimension_width_equal_to: "Bildbreite muss genau %{length} Pixel sein"
17
17
  dimension_height_equal_to: "Bildhöhe muss genau %{length} Pixel sein"
18
+ aspect_ratio_not_square: "muss quadratisch sein"
19
+ aspect_ratio_not_portrait: "muss Hochformat sein"
20
+ aspect_ratio_not_landscape: "muss Querformat sein"
21
+ aspect_ratio_is_not: "muss ein Bildseitenverhältnis von %{aspect_ratio} haben"
22
+ aspect_ratio_unknown: "hat ein unbekanntes Bildseitenverhältnis"
@@ -0,0 +1,22 @@
1
+ es:
2
+ errors:
3
+ messages:
4
+ content_type_invalid: "tiene un tipo de contenido inválido"
5
+ file_size_out_of_range: "tamaño %{file_size} no está entre el rango requerido"
6
+ limit_out_of_range: "el número total está fuera de rango"
7
+ image_metadata_missing: "no es una imagen válida"
8
+ dimension_min_inclusion: "debe ser mayor o igual a %{width} x %{height} pixel"
9
+ dimension_max_inclusion: "debe ser menor o igual a %{width} x %{height} pixel"
10
+ dimension_width_inclusion: "el ancho no se incluye entre %{min} y %{max} pixel"
11
+ dimension_height_inclusion: "la altura no se incluye entre %{min} y %{max} pixel"
12
+ dimension_width_greater_than_or_equal_to: "el ancho debe ser mayor o igual a %{length} pixel"
13
+ dimension_height_greater_than_or_equal_to: "la altura debe ser mayor o igual a %{length} pixel"
14
+ dimension_width_less_than_or_equal_to: "el ancho debe ser menor o igual a %{length} pixel"
15
+ dimension_height_less_than_or_equal_to: "la altura debe ser menor o igual a %{length} pixel"
16
+ dimension_width_equal_to: "el ancho debe ser igual a %{length} pixel"
17
+ dimension_height_equal_to: "la altura debe ser igual a %{length} pixel"
18
+ aspect_ratio_not_square: "debe ser una imagen cuadrada"
19
+ aspect_ratio_not_portrait: "debe ser una imagen vertical"
20
+ aspect_ratio_not_landscape: "debe ser una imagen apaisada"
21
+ aspect_ratio_is_not: "debe tener una relación de aspecto de %{aspect_ratio}"
22
+ aspect_ratio_unknown: "tiene una relación de aspecto desconocida"
@@ -0,0 +1,22 @@
1
+ it:
2
+ errors:
3
+ messages:
4
+ content_type_invalid: "ha un tipo di contenuto non valido"
5
+ file_size_out_of_range: "la dimensione del file %{file_size} non è compresa nell’intervallo consentito"
6
+ limit_out_of_range: "il valore è al di fuori dell’intervallo consentito"
7
+ image_metadata_missing: "non è un'immagine valida"
8
+ dimension_min_inclusion: "deve essere maggiore o uguale a %{width} x %{height} pixel"
9
+ dimension_max_inclusion: "deve essere minore o uguale a %{width} x %{height} pixel"
10
+ dimension_width_inclusion: "la larghezza deve essere compresa tra %{min} e %{max} pixel"
11
+ dimension_height_inclusion: "l’altezza deve essere compresa tra %{min} e %{max} pixel"
12
+ dimension_width_greater_than_or_equal_to: "la larghezza deve essere maggiore o uguale a %{length} pixel"
13
+ dimension_height_greater_than_or_equal_to: "l’altezza deve essere maggiore o uguale a %{length} pixel"
14
+ dimension_width_less_than_or_equal_to: "la larghezza deve essere minore o uguale a %{length} pixel"
15
+ dimension_height_less_than_or_equal_to: "l’altezza deve essere minore o uguale a %{length} pixel"
16
+ dimension_width_equal_to: "la larghezza deve essere pari a %{length} pixel"
17
+ dimension_height_equal_to: "l’altezza deve essere pari a %{length} pixel"
18
+ aspect_ratio_not_square: "deve essere un’immagine quadrata"
19
+ aspect_ratio_not_portrait: "l’orientamento dell’immagine deve essere verticale"
20
+ aspect_ratio_not_landscape: "l’orientamento dell’immagine deve essere orizzontale"
21
+ aspect_ratio_is_not: "deve avere un rapporto altezza / larghezza di %{aspect_ratio}"
22
+ aspect_ratio_unknown: "ha un rapporto altezza / larghezza sconosciuto"
@@ -0,0 +1,22 @@
1
+ nl:
2
+ errors:
3
+ messages:
4
+ content_type_invalid: "heeft een ongeldig inhoudstype"
5
+ file_size_out_of_range: "bestandsgrootte %{file_size} valt niet tussen het vereiste bereik"
6
+ limit_out_of_range: "totaal aantal valt buiten het vereiste bereik"
7
+ image_metadata_missing: "is geen geldige afbeelding"
8
+ dimension_min_inclusion: "moet groter of gelijk zijn aan %{width} x %{height} pixels"
9
+ dimension_max_inclusion: "moet kleiner of gelijk zijn aan %{width} x %{height} pixels"
10
+ dimension_width_inclusion: "breedte niet tussen de %{min} en %{max} pixels"
11
+ dimension_height_inclusion: "hoogte niet tussen de %{min} en %{max} pixels"
12
+ dimension_width_greater_than_or_equal_to: "breedte moet groter of gelijk zijn aan %{length} pixels"
13
+ dimension_height_greater_than_or_equal_to: "hoogte moet groter of gelijk zijn aan %{length} pixels"
14
+ dimension_width_less_than_or_equal_to: "breedte moet kleiner of gelijk zijn aan %{length} pixels"
15
+ dimension_height_less_than_or_equal_to: "hoogte moet kleiner of gelijk zijn aan %{length} pixels"
16
+ dimension_width_equal_to: "breedte moet gelijk zijn aan %{length} pixels"
17
+ dimension_height_equal_to: "hoogte moet gelijk zijn aan %{length} pixels"
18
+ aspect_ratio_not_square: "moet een vierkante afbeelding zijn"
19
+ aspect_ratio_not_portrait: "moet een staande afbeelding zijn"
20
+ aspect_ratio_not_landscape: "moet een liggende afbeelding zijn"
21
+ aspect_ratio_is_not: "moet een beeldverhouding hebben van %{aspect_ratio}"
22
+ aspect_ratio_unknown: "heeft een onbekende beeldverhouding"
@@ -0,0 +1,22 @@
1
+ pl:
2
+ errors:
3
+ messages:
4
+ content_type_invalid: "jest nieprawidłowego typu"
5
+ file_size_out_of_range: "rozmiar %{file_size} nie zawiera się w dopuszczalnym zakresie"
6
+ limit_out_of_range: "ilość przekracza dopuszczalny zakres"
7
+ image_metadata_missing: "nie jest prawidłowym obrazem"
8
+ dimension_min_inclusion: "musi być równe lub większe od %{width} x %{height} pixeli"
9
+ dimension_max_inclusion: "musi być równe lub mniejsze od %{width} x %{height} pixeli"
10
+ dimension_width_inclusion: "szerokość musi wynosić od %{min} do %{max} pixeli"
11
+ dimension_height_inclusion: "wysokość musi wynosić od %{min} do %{max} pixeli"
12
+ dimension_width_greater_than_or_equal_to: "szerokość musi mieć co najmniej %{length} pixeli"
13
+ dimension_height_greater_than_or_equal_to: "wysokość musi mieć co najmniej %{length} pixeli"
14
+ dimension_width_less_than_or_equal_to: "szerokość musi mieć co najwyżej %{length} pixeli"
15
+ dimension_height_less_than_or_equal_to: "wysokość musi mieć co najwyżej %{length} pixeli"
16
+ dimension_width_equal_to: "szerokość musi wynosić %{length} pixeli"
17
+ dimension_height_equal_to: "wysokość musi wynosić %{length} pixeli"
18
+ aspect_ratio_not_square: "musi mieć proporcje kwadratu"
19
+ aspect_ratio_not_portrait: "musi mieć proporcje portretu"
20
+ aspect_ratio_not_landscape: "musi mieć proporcje pejzażu"
21
+ aspect_ratio_is_not: "musi mieć proporcje %{aspect_ratio}"
22
+ aspect_ratio_unknown: "ma nieokreślone proporcje"
@@ -0,0 +1,22 @@
1
+ tr:
2
+ errors:
3
+ messages:
4
+ content_type_invalid: "geçersiz dosya tipine sahip"
5
+ file_size_out_of_range: "dosya boyutu %{file_size} gerekli aralık dışında"
6
+ limit_out_of_range: "toplam miktar aralık dışında"
7
+ image_metadata_missing: "geçerli bir imaj değil"
8
+ dimension_min_inclusion: "%{width} x %{height} piksele eşit ya da büyük olmalı"
9
+ dimension_max_inclusion: "%{width} x %{height} piksele eşit ya da küçük olmalı"
10
+ dimension_width_inclusion: "en %{min} ve %{max} piksel aralığı dışında"
11
+ dimension_height_inclusion: "boy %{min} ve %{max} piksel aralığı dışında"
12
+ dimension_width_greater_than_or_equal_to: "en %{length} piksele eşit ya da büyük olmalı"
13
+ dimension_height_greater_than_or_equal_to: "boy %{length} piksele eşit ya da büyük olmalı"
14
+ dimension_width_less_than_or_equal_to: "en %{length} piksele eşit ya da küçük olmalı"
15
+ dimension_height_less_than_or_equal_to: "boy %{length} piksele eşit ya da küçük olmalı"
16
+ dimension_width_equal_to: "en %{length} piksele eşit olmalı"
17
+ dimension_height_equal_to: "boy %{length} piksele eşit olmalı"
18
+ aspect_ratio_not_square: "kare bir imaj olmalı"
19
+ aspect_ratio_not_portrait: "dikey bir imaj olmalı"
20
+ aspect_ratio_not_landscape: "yatay bir imaj olmalı"
21
+ aspect_ratio_is_not: "%{aspect_ratio} en boy oranına sahip olmalı"
22
+ aspect_ratio_unknown: "bilinmeyen en boy oranı"
@@ -1,22 +1,22 @@
1
1
  uk:
2
2
  errors:
3
3
  messages:
4
- content_type_invalid: "має неприпустимий тип вмісту"
5
- file_size_out_of_range: "розмір %{file_size} більше необхідного"
6
- limit_out_of_range: "кількість файлів більше необхідного"
7
- image_metadata_missing: "не є допустимим зображенням"
8
- dimension_min_inclusion: "мусить бути більше або дорівнювати %{width} x %{height} пікселям"
9
- dimension_max_inclusion: "мусить бути менше або дорівнювати %{width} x %{height} пікселям"
10
- dimension_width_inclusion: "ширина не включена між %{min} і %{max} пікселям"
11
- dimension_height_inclusion: "висота не включена між %{min} і %{max} пікселям"
12
- dimension_width_greater_than_or_equal_to: "ширина мусить бути більше або дорівнювати %{length} пікселям"
13
- dimension_height_greater_than_or_equal_to: "висота мусить бути більше або дорівнювати %{length} пікселям"
14
- dimension_width_less_than_or_equal_to: "ширина мусить бути менше або дорівнювати %{length} пікселям"
15
- dimension_height_less_than_or_equal_to: "висота мусить бути менше або дорівнювати %{length} пікселям"
16
- dimension_width_equal_to: "ширина мусить дорівнювати %{length} пікселям"
17
- dimension_height_equal_to: "висота мусить дорівнювати %{length} пікселям"
18
- aspect_ratio_not_square: "мусить бути квадратне зображення"
19
- aspect_ratio_not_portrait: "мусить бути портретне зображення"
20
- aspect_ratio_not_landscape: "мусить бути пейзажне зображення"
21
- aspect_ratio_is_not: "мусить мати співвідношення сторін %{aspect_ratio}"
22
- aspect_ratio_unknown: "має невідоме співвідношення сторін"
4
+ content_type_invalid: "має неприпустимий тип вмісту"
5
+ file_size_out_of_range: "розмір %{file_size} більше необхідного"
6
+ limit_out_of_range: "кількість файлів більше необхідного"
7
+ image_metadata_missing: "не є допустимим зображенням"
8
+ dimension_min_inclusion: "мусить бути більше або дорівнювати %{width} x %{height} пікселям"
9
+ dimension_max_inclusion: "мусить бути менше або дорівнювати %{width} x %{height} пікселям"
10
+ dimension_width_inclusion: "ширина не включена між %{min} і %{max} пікселям"
11
+ dimension_height_inclusion: "висота не включена між %{min} і %{max} пікселям"
12
+ dimension_width_greater_than_or_equal_to: "ширина мусить бути більше або дорівнювати %{length} пікселям"
13
+ dimension_height_greater_than_or_equal_to: "висота мусить бути більше або дорівнювати %{length} пікселям"
14
+ dimension_width_less_than_or_equal_to: "ширина мусить бути менше або дорівнювати %{length} пікселям"
15
+ dimension_height_less_than_or_equal_to: "висота мусить бути менше або дорівнювати %{length} пікселям"
16
+ dimension_width_equal_to: "ширина мусить дорівнювати %{length} пікселям"
17
+ dimension_height_equal_to: "висота мусить дорівнювати %{length} пікселям"
18
+ aspect_ratio_not_square: "мусить бути квадратне зображення"
19
+ aspect_ratio_not_portrait: "мусить бути портретне зображення"
20
+ aspect_ratio_not_landscape: "мусить бути пейзажне зображення"
21
+ aspect_ratio_is_not: "мусить мати співвідношення сторін %{aspect_ratio}"
22
+ aspect_ratio_unknown: "має невідоме співвідношення сторін"
@@ -0,0 +1,22 @@
1
+ vi:
2
+ errors:
3
+ messages:
4
+ content_type_invalid: "tệp không hợp lệ"
5
+ file_size_out_of_range: "kích thước %{file_size} vượt giới hạn"
6
+ limit_out_of_range: "tổng số tệp vượt giới hạn"
7
+ image_metadata_missing: "không phải là ảnh"
8
+ dimension_min_inclusion: "phải lớn hơn hoặc bằng %{width} x %{height} pixel"
9
+ dimension_max_inclusion: "phải nhỏ hơn hoặc bằng %{width} x %{height} pixel"
10
+ dimension_width_inclusion: "chiều rộng không nằm trong %{min} và %{max} pixel"
11
+ dimension_height_inclusion: "chiều cao không nằm trong %{min} và %{max} pixel"
12
+ dimension_width_greater_than_or_equal_to: "chiều rộng phải lớn hơn hoặc bằng %{length} pixel"
13
+ dimension_height_greater_than_or_equal_to: "chiều cao phải lớn hơn hoặc bằng %{length} pixel"
14
+ dimension_width_less_than_or_equal_to: "chiều rộng phải nhỏ hơn hoặc bằng %{length} pixel"
15
+ dimension_height_less_than_or_equal_to: "chiều cao phải nhỏ hơn hoặc bằng %{length} pixel"
16
+ dimension_width_equal_to: "chiều rộng phải bằng %{length} pixel"
17
+ dimension_height_equal_to: "chiều cao phải bằng %{length} pixel"
18
+ aspect_ratio_not_square: "phải là ảnh hình vuông"
19
+ aspect_ratio_not_portrait: "phải là ảnh đứng"
20
+ aspect_ratio_not_landscape: "phải là ảnh ngang"
21
+ aspect_ratio_is_not: "phải có tỉ lệ ảnh %{aspect_ratio}"
22
+ aspect_ratio_unknown: "tỉ lệ ảnh không xác định"
@@ -5,7 +5,10 @@ module ActiveStorageValidations
5
5
  def validate_each(record, attribute, _value)
6
6
  return if record.send(attribute).attached?
7
7
 
8
- record.errors.add(attribute, :blank)
8
+ errors_options = {}
9
+ errors_options[:message] = options[:message] if options[:message].present?
10
+
11
+ record.errors.add(attribute, :blank, **errors_options)
9
12
  end
10
13
  end
11
14
  end
@@ -14,14 +14,21 @@ module ActiveStorageValidations
14
14
  next if is_valid?(file)
15
15
 
16
16
  errors_options[:content_type] = content_type(file)
17
- record.errors.add(attribute, :content_type_invalid, errors_options)
17
+ record.errors.add(attribute, :content_type_invalid, **errors_options)
18
18
  break
19
19
  end
20
20
  end
21
21
 
22
22
  def types
23
23
  (Array.wrap(options[:with]) + Array.wrap(options[:in])).compact.map do |type|
24
- Mime[type] || type
24
+ if type.is_a?(Regexp)
25
+ type
26
+ elsif type.is_a?(String) && type =~ %r{\A\w+/[-+.\w]+\z} # mime-type-ish string
27
+ type
28
+ else
29
+ Mime[type] || raise(ArgumentError, "content_type must be one of Regxep,"\
30
+ " supported mime types (e.g. :png, 'jpg'), or mime type String ('image/jpeg')")
31
+ end
25
32
  end
26
33
  end
27
34
 
@@ -36,10 +43,9 @@ module ActiveStorageValidations
36
43
  end
37
44
 
38
45
  def is_valid?(file)
39
- if options[:with].is_a?(Regexp)
40
- options[:with].match?(content_type(file).to_s)
41
- else
42
- content_type(file).in?(types)
46
+ file_type = content_type(file)
47
+ types.any? do |type|
48
+ type == file_type || (type.is_a?(Regexp) && type.match?(file_type.to_s))
43
49
  end
44
50
  end
45
51
  end
@@ -52,7 +52,7 @@ module ActiveStorageValidations
52
52
  # Rails 5
53
53
  def validate_each(record, attribute, _value)
54
54
  return true unless record.send(attribute).attached?
55
-
55
+
56
56
  files = Array.wrap(record.send(attribute))
57
57
  files.each do |file|
58
58
  # Analyze file first if not analyzed to get all required metadata.
@@ -110,7 +110,7 @@ module ActiveStorageValidations
110
110
  else
111
111
  if file_metadata[length] != options[length]
112
112
  add_error(record, attribute, options[:message].presence || :"dimension_#{length}_equal_to", length: options[length])
113
- return false
113
+ return false
114
114
  end
115
115
  end
116
116
  end
@@ -119,11 +119,11 @@ module ActiveStorageValidations
119
119
  true # valid file
120
120
  end
121
121
 
122
- def add_error(record, attribute, type, *attrs)
122
+ def add_error(record, attribute, type, **attrs)
123
123
  key = options[:message].presence || type
124
124
  return if record.errors.added?(attribute, key)
125
- record.errors.add(attribute, key, *attrs)
126
- end
125
+ record.errors.add(attribute, key, **attrs)
126
+ end
127
127
 
128
128
  end
129
129
  end
@@ -17,7 +17,7 @@ module ActiveStorageValidations
17
17
  errors_options = { min: options[:min], max: options[:max] }
18
18
 
19
19
  return true if files_count_valid?(files.count)
20
- record.errors.add(attribute, options[:message].presence || :limit_out_of_range, errors_options)
20
+ record.errors.add(attribute, options[:message].presence || :limit_out_of_range, **errors_options)
21
21
  end
22
22
 
23
23
  def files_count_valid?(count)
@@ -16,9 +16,8 @@ module ActiveStorageValidations
16
16
  end
17
17
 
18
18
  def matches?(subject)
19
- @subject = subject.is_a?(Class) ? subject : subject.class
20
-
21
- invalid_when_not_attached && valid_when_attached
19
+ @subject = subject.is_a?(Class) ? subject.new : subject
20
+ responds_to_methods && valid_when_attached && invalid_when_not_attached
22
21
  end
23
22
 
24
23
  def failure_message
@@ -31,17 +30,25 @@ module ActiveStorageValidations
31
30
 
32
31
  private
33
32
 
33
+ def responds_to_methods
34
+ @subject.respond_to?(@attribute_name) &&
35
+ @subject.public_send(@attribute_name).respond_to?(:attach) &&
36
+ @subject.public_send(@attribute_name).respond_to?(:detach)
37
+ end
38
+
34
39
  def valid_when_attached
35
- instance = @subject.new
36
- instance.public_send(@attribute_name).attach(attachable)
37
- instance.validate
38
- instance.errors.details[@attribute_name].exclude?(error: :blank)
40
+ @subject.public_send(@attribute_name).attach(attachable) unless @subject.public_send(@attribute_name).attached?
41
+ @subject.validate
42
+ @subject.errors.details[@attribute_name].exclude?(error: :blank)
39
43
  end
40
44
 
41
45
  def invalid_when_not_attached
42
- instance = @subject.new
43
- instance.validate
44
- instance.errors.details[@attribute_name].include?(error: :blank)
46
+ @subject.public_send(@attribute_name).detach
47
+ # Unset the direct relation since `detach` on an unpersisted record does not set `attached?` to false.
48
+ @subject.public_send("#{@attribute_name}=", nil)
49
+
50
+ @subject.validate
51
+ @subject.errors.details[@attribute_name].include?(error: :blank)
45
52
  end
46
53
 
47
54
  def attachable
@@ -29,7 +29,7 @@ module ActiveStorageValidations
29
29
 
30
30
  def matches?(subject)
31
31
  @subject = subject.is_a?(Class) ? subject.new : subject
32
- allowed_types_allowed? && rejected_types_rejected?
32
+ responds_to_methods && allowed_types_allowed? && rejected_types_rejected?
33
33
  end
34
34
 
35
35
  def failure_message
@@ -46,6 +46,12 @@ module ActiveStorageValidations
46
46
 
47
47
  protected
48
48
 
49
+ def responds_to_methods
50
+ @subject.respond_to?(@attribute_name) &&
51
+ @subject.public_send(@attribute_name).respond_to?(:attach) &&
52
+ @subject.public_send(@attribute_name).respond_to?(:detach)
53
+ end
54
+
49
55
  def allowed_types
50
56
  @allowed_types || []
51
57
  end
@@ -10,6 +10,7 @@ module ActiveStorageValidations
10
10
  def initialize(attribute_name)
11
11
  @attribute_name = attribute_name
12
12
  @width_min = @width_max = @height_min = @height_max = nil
13
+ @custom_message = nil
13
14
  end
14
15
 
15
16
  def description
@@ -26,6 +27,11 @@ module ActiveStorageValidations
26
27
  self
27
28
  end
28
29
 
30
+ def with_message(message)
31
+ @custom_message = message
32
+ self
33
+ end
34
+
29
35
  def width(width)
30
36
  @width_min = @width_max = width
31
37
  self
@@ -58,7 +64,8 @@ module ActiveStorageValidations
58
64
 
59
65
  def matches?(subject)
60
66
  @subject = subject.is_a?(Class) ? subject.new : subject
61
- width_smaller_than_min? && width_larger_than_min? && width_smaller_than_max? && width_larger_than_max? && width_equals? &&
67
+ responds_to_methods &&
68
+ width_smaller_than_min? && width_larger_than_min? && width_smaller_than_max? && width_larger_than_max? && width_equals? &&
62
69
  height_smaller_than_min? && height_larger_than_min? && height_smaller_than_max? && height_larger_than_max? && height_equals?
63
70
  end
64
71
 
@@ -72,6 +79,12 @@ module ActiveStorageValidations
72
79
 
73
80
  protected
74
81
 
82
+ def responds_to_methods
83
+ @subject.respond_to?(@attribute_name) &&
84
+ @subject.public_send(@attribute_name).respond_to?(:attach) &&
85
+ @subject.public_send(@attribute_name).respond_to?(:detach)
86
+ end
87
+
75
88
  def valid_width
76
89
  ((@width_min || 0) + (@width_max || 2000)) / 2
77
90
  end
@@ -126,7 +139,8 @@ module ActiveStorageValidations
126
139
  attachment = @subject.public_send(@attribute_name)
127
140
  Matchers.mock_metadata(attachment, width, height) do
128
141
  @subject.validate
129
- @subject.errors.details[@attribute_name].all? { |error| error[:error].to_s.exclude?("dimension_#{check}") }
142
+ exclude_error_message = @custom_message || "dimension_#{check}"
143
+ @subject.errors.details[@attribute_name].all? { |error| error[:error].to_s.exclude?(exclude_error_message) }
130
144
  end
131
145
  end
132
146
 
@@ -45,7 +45,7 @@ module ActiveStorageValidations
45
45
 
46
46
  def matches?(subject)
47
47
  @subject = subject.is_a?(Class) ? subject.new : subject
48
- lower_than_low? && higher_than_low? && lower_than_high? && higher_than_high?
48
+ responds_to_methods && lower_than_low? && higher_than_low? && lower_than_high? && higher_than_high?
49
49
  end
50
50
 
51
51
  def failure_message
@@ -58,6 +58,12 @@ module ActiveStorageValidations
58
58
 
59
59
  protected
60
60
 
61
+ def responds_to_methods
62
+ @subject.respond_to?(@attribute_name) &&
63
+ @subject.public_send(@attribute_name).respond_to?(:attach) &&
64
+ @subject.public_send(@attribute_name).respond_to?(:detach)
65
+ end
66
+
61
67
  def lower_than_low?
62
68
  @low.nil? || !passes_validation_with_size(@low - 1)
63
69
  end
@@ -21,7 +21,17 @@ module ActiveStorageValidations
21
21
  def read_image
22
22
  is_string = file.is_a?(String)
23
23
  if is_string || file.is_a?(ActiveStorage::Blob)
24
- blob = is_string ? ActiveStorage::Blob.find_signed(file) : file
24
+ if is_string
25
+ # If Rails 5.2 or 6.0, use `find_signed`
26
+ if Rails::VERSION::MAJOR < 6 || (Rails::VERSION::MAJOR == 6 && Rails::VERSION::MINOR == 0)
27
+ blob = ActiveStorage::Blob.find_signed(file)
28
+ # If Rails 6.1 or higher, use `find_signed!`
29
+ elsif Rails::VERSION::MAJOR > 6 || (Rails::VERSION::MAJOR == 6 && Rails::VERSION::MINOR >= 1)
30
+ blob = ActiveStorage::Blob.find_signed!(file)
31
+ end
32
+ else
33
+ blob = file
34
+ end
25
35
 
26
36
  tempfile = Tempfile.new(["ActiveStorage-#{blob.id}-", blob.filename.extension_with_delimiter])
27
37
  tempfile.binmode
@@ -25,7 +25,7 @@ module ActiveStorageValidations
25
25
  next if content_size_valid?(file.blob.byte_size)
26
26
 
27
27
  errors_options[:file_size] = number_to_human_size(file.blob.byte_size)
28
- record.errors.add(attribute, :file_size_out_of_range, errors_options)
28
+ record.errors.add(attribute, :file_size_out_of_range, **errors_options)
29
29
  break
30
30
  end
31
31
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveStorageValidations
4
- VERSION = '0.8.9'
4
+ VERSION = '0.9.4'
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.8.9
4
+ version: 0.9.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Igor Kasyanchuk
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-05-16 00:00:00.000000000 Z
11
+ date: 2021-06-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -25,35 +25,35 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: 5.2.0
27
27
  - !ruby/object:Gem::Dependency
28
- name: mini_magick
28
+ name: combustion
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ">="
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 4.9.5
33
+ version: '1.3'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ">="
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 4.9.5
40
+ version: '1.3'
41
41
  - !ruby/object:Gem::Dependency
42
- name: pry
42
+ name: mini_magick
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ">="
46
46
  - !ruby/object:Gem::Version
47
- version: '0'
47
+ version: 4.9.5
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
- version: '0'
54
+ version: 4.9.5
55
55
  - !ruby/object:Gem::Dependency
56
- name: rubocop
56
+ name: pry
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - ">="
@@ -67,7 +67,7 @@ dependencies:
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
- name: sqlite3
70
+ name: rubocop
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - ">="
@@ -81,7 +81,7 @@ dependencies:
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
- name: coffee-rails
84
+ name: sqlite3
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - ">="
@@ -106,11 +106,17 @@ files:
106
106
  - Rakefile
107
107
  - config/locales/de.yml
108
108
  - config/locales/en.yml
109
+ - config/locales/es.yml
109
110
  - config/locales/fr.yml
111
+ - config/locales/it.yml
110
112
  - config/locales/ja.yml
113
+ - config/locales/nl.yml
114
+ - config/locales/pl.yml
111
115
  - config/locales/pt-BR.yml
112
116
  - config/locales/ru.yml
117
+ - config/locales/tr.yml
113
118
  - config/locales/uk.yml
119
+ - config/locales/vi.yml
114
120
  - lib/active_storage_validations.rb
115
121
  - lib/active_storage_validations/aspect_ratio_validator.rb
116
122
  - lib/active_storage_validations/attached_validator.rb