active_storage_validations 1.0.4 → 1.1.0

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: fe9e0494c1bf81d0f0a00c649abce9de1ff9c0dc8782a6a39253bdf1a890361d
4
- data.tar.gz: '0690ff0b6a259b35d074b8c81bad13ac4c699dbb1a3caca2b5b0b2b3d8b143ce'
3
+ metadata.gz: f41ec7bce11523af0deebbac7aac427c19a0c5f9788c3719ff94122468781a79
4
+ data.tar.gz: aef955507fb8c8b3a42a27820ea213347f03c49373eef27b44a99e764456b77d
5
5
  SHA512:
6
- metadata.gz: 040ea6fc5660f163ba936b0b384eb515bad557f8d489bc75560e745b03011e97bc699c13e220f48f2e617b72abb70163f86cb7bdeb68522da48acb3508642679
7
- data.tar.gz: e014d61d14631626179784ce0f7e31a65264103264d0b39666c720e135e6b34b68a64f374157174a0f974644cfdb8b22deeeee365c2d29d6ccb7394e290edab0
6
+ metadata.gz: 19b37c9826cda8b8864631c77e5a3eabf1f8164279ad2c64beebd5f60b82e03dc39bdb466d516fa161b81b9ca3b0d98913bd04b32950e3b98b3ab28632941a91
7
+ data.tar.gz: d12ffa26482ae3e3feead8c3b658f0aa4331dd08a16b87ba9d7e639bc78a25499bda8ba27ae81c0db39d7d0c9bd59bc9f136b56500d97ae5a0f8b2bd85a5f112
data/README.md CHANGED
@@ -149,7 +149,11 @@ en:
149
149
  errors:
150
150
  messages:
151
151
  content_type_invalid: "has an invalid content type"
152
- file_size_out_of_range: "size %{file_size} is not between required range"
152
+ file_size_not_less_than: "file size must be less than %{max_size} (current size is %{file_size})"
153
+ file_size_not_less_than_or_equal_to: "file size must be less than or equal to %{max_size} (current size is %{file_size})"
154
+ file_size_not_greater_than: "file size must be greater than %{min_size} (current size is %{file_size})"
155
+ file_size_not_greater_than_or_equal_to: "file size must be greater than or equal to %{min_size} (current size is %{file_size})"
156
+ file_size_not_between: "file size must be between %{min_size} and %{max_size} (current size is %{file_size})"
153
157
  limit_out_of_range: "total number is out of range"
154
158
  image_metadata_missing: "is not a valid image"
155
159
  dimension_min_inclusion: "must be greater than or equal to %{width} x %{height} pixel."
@@ -172,17 +176,21 @@ en:
172
176
 
173
177
  In some cases, Active Storage Validations provides variables to help you customize messages:
174
178
 
175
- The "content_type_invalid" key has two variables that you can use, a variable named "content_type" containing the content type of the send file and a variable named "authorized_types" containing the list of authorized content types.
176
-
177
- The variables are not used by default to leave the choice to the user.
179
+ ### Content type
180
+ The `content_type_invalid` key has two variables that you can use:
181
+ - `content_type` containing the content type of the sent file
182
+ - `authorized_types` containing the list of authorized content types
178
183
 
179
184
  For example :
180
185
 
181
186
  ```yml
182
- content_type_invalid: "has an invalid content type : %{content_type}"
187
+ content_type_invalid: "has an invalid content type : %{content_type}, authorized types are %{authorized_types}"
183
188
  ```
184
189
 
185
- Also the "limit_out_of_range" key supports two variables the "min" and "max".
190
+ ### Number of files
191
+ The `limit_out_of_range` key supports two variables that you can use:
192
+ - `min` containing the minimum number of files
193
+ - `max` containing the maximum number of files
186
194
 
187
195
  For example :
188
196
 
@@ -190,6 +198,28 @@ For example :
190
198
  limit_out_of_range: "total number is out of range. range: [%{min}, %{max}]"
191
199
  ```
192
200
 
201
+ ### File size
202
+ The keys starting with `file_size_not_` support three variables that you can use:
203
+ - `file_size` containing the current file size
204
+ - `min` containing the minimum file size
205
+ - `max` containing the maxmimum file size
206
+
207
+ For example :
208
+
209
+ ```yml
210
+ file_size_not_between: "file size must be between %{min_size} and %{max_size} (current size is %{file_size})"
211
+ ```
212
+
213
+ ### Aspect ratio
214
+ The keys starting with `aspect_ratio_` support one variable that you can use:
215
+ - `aspect_ratio` containing the expected aspect ratio, especially usefull for custom aspect ratio
216
+
217
+ For example :
218
+
219
+ ```yml
220
+ aspect_ratio_is_not: "must be a %{aspect_ratio} image"
221
+ ```
222
+
193
223
  ## Installation
194
224
 
195
225
  Add this line to your application's Gemfile:
@@ -240,9 +270,11 @@ Example (Note that the options are chainable):
240
270
  ```ruby
241
271
  describe User do
242
272
  it { is_expected.to validate_attached_of(:avatar) }
273
+ it { is_expected.to validate_attached_of(:avatar).with_message('must not be blank') }
243
274
 
244
275
  it { is_expected.to validate_content_type_of(:avatar).allowing('image/png', 'image/gif') }
245
276
  it { is_expected.to validate_content_type_of(:avatar).rejecting('text/plain', 'text/xml') }
277
+ it { is_expected.to validate_content_type_of(:avatar).rejecting('text/plain', 'text/xml').with_message("must be an authorized type") }
246
278
 
247
279
  it { is_expected.to validate_dimensions_of(:avatar).width(250) }
248
280
  it { is_expected.to validate_dimensions_of(:avatar).height(200) }
@@ -257,6 +289,7 @@ describe User do
257
289
  it { is_expected.to validate_size_of(:avatar).less_than(50.kilobytes) }
258
290
  it { is_expected.to validate_size_of(:avatar).less_than_or_equal_to(50.kilobytes) }
259
291
  it { is_expected.to validate_size_of(:avatar).greater_than(1.kilobyte) }
292
+ it { is_expected.to validate_size_of(:avatar).greater_than(1.kilobyte).with_message('is not in required file size range') }
260
293
  it { is_expected.to validate_size_of(:avatar).greater_than_or_equal_to(1.kilobyte) }
261
294
  it { is_expected.to validate_size_of(:avatar).between(100..500.kilobytes) }
262
295
  end
@@ -282,9 +315,11 @@ Example (Note that the options are chainable):
282
315
  ```ruby
283
316
  class UserTest < ActiveSupport::TestCase
284
317
  should validate_attached_of(:avatar)
318
+ should validate_attached_of(:avatar).with_message('must not be blank')
285
319
 
286
320
  should validate_content_type_of(:avatar).allowing('image/png', 'image/gif')
287
321
  should validate_content_type_of(:avatar).rejecting('text/plain', 'text/xml')
322
+ should validate_content_type_of(:avatar).rejecting('text/plain', 'text/xml').with_message("must be an authorized type")
288
323
 
289
324
  should validate_dimensions_of(:avatar).width(250)
290
325
  should validate_dimensions_of(:avatar).height(200)
@@ -299,6 +334,7 @@ class UserTest < ActiveSupport::TestCase
299
334
  should validate_size_of(:avatar).less_than(50.kilobytes)
300
335
  should validate_size_of(:avatar).less_than_or_equal_to(50.kilobytes)
301
336
  should validate_size_of(:avatar).greater_than(1.kilobyte)
337
+ should validate_size_of(:avatar).greater_than(1.kilobyte).with_message('is not in required file size range')
302
338
  should validate_size_of(:avatar).greater_than_or_equal_to(1.kilobyte)
303
339
  should validate_size_of(:avatar).between(100..500.kilobytes)
304
340
  end
@@ -308,7 +344,6 @@ end
308
344
 
309
345
  * verify with remote storages (s3, etc)
310
346
  * verify how it works with direct upload
311
- * better error message when content_size is invalid
312
347
  * add more translations
313
348
 
314
349
  ## Tests & Contributing
@@ -346,8 +381,12 @@ BUNDLE_GEMFILE=gemfiles/rails_next.gemfile bundle exec rake test
346
381
  This is a Rails issue, and is fixed in Rails 6.
347
382
 
348
383
  ## Contributing
384
+
349
385
  You are welcome to contribute.
350
386
 
387
+ [<img src="https://opensource-heroes.com/svg/embed/igorkasyanchuk/active_storage_validations"
388
+ />](https://opensource-heroes.com/r/igorkasyanchuk/active_storage_validations)
389
+
351
390
  ## Contributors (BIG THANK YOU)
352
391
  - https://github.com/schweigert
353
392
  - https://github.com/tleneveu
@@ -403,6 +442,11 @@ You are welcome to contribute.
403
442
  - https://github.com/sobrinho
404
443
  - https://github.com/iainbeeston
405
444
  - https://github.com/marckohlbrugge
445
+ - https://github.com/Mth0158
446
+ - https://github.com/technicalpickles
447
+ - https://github.com/ricsdeol
448
+ - https://github.com/Fonsan
449
+
406
450
 
407
451
  ## License
408
452
 
@@ -2,7 +2,11 @@ de:
2
2
  errors:
3
3
  messages:
4
4
  content_type_invalid: "hat einen ungültigen Dateityp"
5
- file_size_out_of_range: "Dateigröße %{file_size} liegt nicht im erlaubten Bereich"
5
+ file_size_not_less_than: "Dateigröße muss kleiner als %{max_size} sein (aktuelle Dateigröße ist %{file_size})"
6
+ file_size_not_less_than_or_equal_to: "Dateigröße muss kleiner oder gleich %{max_size} sein (aktuelle Dateigröße ist %{file_size})"
7
+ file_size_not_greater_than: "Dateigröße muss größer als %{min_size} sein (aktuelle Dateigröße ist %{file_size})"
8
+ file_size_not_greater_than_or_equal_to: "Dateigröße muss größer oder gleich %{min_size} sein (aktuelle Dateigröße ist %{file_size})"
9
+ file_size_not_between: "Dateigröße muss zwischen %{min_size} und %{max_size} liegen (aktuelle Dateigröße ist %{file_size})"
6
10
  limit_out_of_range: "Anzahl ist außerhalb des gültigen Bereichs"
7
11
  image_metadata_missing: "ist kein gültiges Bild"
8
12
  dimension_min_inclusion: "muss größer oder gleich %{width} x %{height} Pixel sein"
@@ -2,7 +2,11 @@ en:
2
2
  errors:
3
3
  messages:
4
4
  content_type_invalid: "has an invalid content type"
5
- file_size_out_of_range: "size %{file_size} is not between required range"
5
+ file_size_not_less_than: "file size must be less than %{max_size} (current size is %{file_size})"
6
+ file_size_not_less_than_or_equal_to: "file size must be less than or equal to %{max_size} (current size is %{file_size})"
7
+ file_size_not_greater_than: "file size must be greater than %{min_size} (current size is %{file_size})"
8
+ file_size_not_greater_than_or_equal_to: "file size must be greater than or equal to %{min_size} (current size is %{file_size})"
9
+ file_size_not_between: "file size must be between %{min_size} and %{max_size} (current size is %{file_size})"
6
10
  limit_out_of_range: "total number is out of range"
7
11
  image_metadata_missing: "is not a valid image"
8
12
  dimension_min_inclusion: "must be greater than or equal to %{width} x %{height} pixel"
@@ -2,7 +2,11 @@ es:
2
2
  errors:
3
3
  messages:
4
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"
5
+ file_size_not_less_than: "el tamaño del archivo debe ser inferior a %{max_size} (el tamaño actual es %{file_size})"
6
+ file_size_not_less_than_or_equal_to: "el tamaño del archivo debe ser menor o igual a %{max_size} (el tamaño actual es %{file_size})"
7
+ file_size_not_greater_than: "el tamaño del archivo debe ser mayor que %{min_size} (el tamaño actual es %{file_size})"
8
+ file_size_not_greater_than_or_equal_to: "el tamaño del archivo debe ser mayor o igual a %{min_size} (el tamaño actual es %{file_size})"
9
+ file_size_not_between: "el tamaño del archivo debe estar entre %{min_size} y %{max_size} (el tamaño actual es %{file_size})"
6
10
  limit_out_of_range: "el número total está fuera de rango"
7
11
  image_metadata_missing: "no es una imagen válida"
8
12
  dimension_min_inclusion: "debe ser mayor o igual a %{width} x %{height} pixel"
@@ -2,7 +2,11 @@ fr:
2
2
  errors:
3
3
  messages:
4
4
  content_type_invalid: "a un type de contenu non valide"
5
- file_size_out_of_range: "la taille %{file_size} n'est pas comprise dans la plage permise"
5
+ file_size_not_less_than: "la taille du fichier doit être inférieure à %{max_size} (la taille actuelle est %{file_size})"
6
+ file_size_not_less_than_or_equal_to: "la taille du fichier doit être inférieure ou égale à %{max_size} (la taille actuelle est %{file_size})"
7
+ file_size_not_greater_than: "la taille du fichier doit être supérieure à %{min_size} (la taille actuelle est %{file_size})"
8
+ file_size_not_greater_than_or_equal_to: "la taille du fichier doit être supérieure ou égale à %{min_size} (la taille actuelle est %{file_size})"
9
+ file_size_not_between: "la taille du fichier doit être comprise entre %{min_size} et %{max_size} (la taille actuelle est %{file_size})"
6
10
  limit_out_of_range: "le nombre total est hors limites"
7
11
  image_metadata_missing: "n'est pas une image valide"
8
12
  dimension_min_inclusion: "doit être supérieur ou égal à %{width} x %{height} pixels"
@@ -2,7 +2,11 @@ it:
2
2
  errors:
3
3
  messages:
4
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"
5
+ file_size_not_less_than: "la dimensione del file deve essere inferiore a %{max_size} (la dimensione attuale è %{file_size})"
6
+ file_size_not_less_than_or_equal_to: "la dimensione del file deve essere minore o uguale a %{max_size} (la dimensione attuale è %{file_size})"
7
+ file_size_not_greater_than: "la dimensione del file deve essere maggiore di %{min_size} (la dimensione attuale è %{file_size})"
8
+ file_size_not_greater_than_or_equal_to: "la dimensione del file deve essere maggiore o uguale a %{min_size} (la dimensione attuale è %{file_size})"
9
+ file_size_not_between: "la dimensione del file deve essere compresa tra %{min_size} e %{max_size} (la dimensione attuale è %{file_size})"
6
10
  limit_out_of_range: "il valore è al di fuori dell’intervallo consentito"
7
11
  image_metadata_missing: "non è un'immagine valida"
8
12
  dimension_min_inclusion: "deve essere maggiore o uguale a %{width} x %{height} pixel"
@@ -2,7 +2,11 @@ ja:
2
2
  errors:
3
3
  messages:
4
4
  content_type_invalid: "のContent Typeが不正です"
5
- file_size_out_of_range: "の容量 %{file_size} が許容範囲外です"
5
+ file_size_not_less_than: "ファイル サイズは %{max_size} 未満にする必要があります (現在のサイズは %{file_size})"
6
+ file_size_not_less_than_or_equal_to: "ファイル サイズは %{max_size} 以下である必要があります (現在のサイズは %{file_size})"
7
+ file_size_not_greater_than: "ファイル サイズは %{min_size} より大きい必要があります (現在のサイズは %{file_size} です)"
8
+ file_size_not_greater_than_or_equal_to: "ファイル サイズは %{min_size} 以上である必要があります (現在のサイズは %{file_size})"
9
+ file_size_not_between: "ファイル サイズは %{min_size} から %{max_size} の間でなければなりません (現在のサイズは %{file_size} です)"
6
10
  limit_out_of_range: "の数が許容範囲外です"
7
11
  image_metadata_missing: "は不正な画像です"
8
12
  dimension_min_inclusion: "は %{width} x %{height} ピクセル以上の大きさにしてください"
@@ -2,7 +2,11 @@ nl:
2
2
  errors:
3
3
  messages:
4
4
  content_type_invalid: "heeft een ongeldig inhoudstype"
5
- file_size_out_of_range: "bestandsgrootte %{file_size} valt niet tussen het vereiste bereik"
5
+ file_size_not_less_than: "bestandsgrootte moet kleiner zijn dan %{max_size} (huidige grootte is %{file_size})"
6
+ file_size_not_less_than_or_equal_to: "bestandsgrootte moet kleiner zijn dan of gelijk zijn aan %{max_size} (huidige grootte is %{file_size})"
7
+ file_size_not_greater_than: "bestandsgrootte moet groter zijn dan %{min_size} (huidige grootte is %{file_size})"
8
+ file_size_not_greater_than_or_equal_to: "bestandsgrootte moet groter zijn dan of gelijk zijn aan %{min_size} (huidige grootte is %{file_size})"
9
+ file_size_not_between: "bestandsgrootte moet tussen %{min_size} en %{max_size} liggen (huidige grootte is %{file_size})"
6
10
  limit_out_of_range: "totaal aantal valt buiten het vereiste bereik"
7
11
  image_metadata_missing: "is geen geldige afbeelding"
8
12
  dimension_min_inclusion: "moet groter of gelijk zijn aan %{width} x %{height} pixels"
@@ -2,7 +2,11 @@ pl:
2
2
  errors:
3
3
  messages:
4
4
  content_type_invalid: "jest nieprawidłowego typu"
5
- file_size_out_of_range: "rozmiar %{file_size} nie zawiera się w dopuszczalnym zakresie"
5
+ file_size_not_less_than: "rozmiar pliku musi być mniejszy niż %{max_size} (obecny rozmiar to %{file_size})"
6
+ file_size_not_less_than_or_equal_to: "rozmiar pliku musi być mniejszy lub równy %{max_size} (obecny rozmiar to %{file_size})"
7
+ file_size_not_greater_than: "rozmiar pliku musi być większy niż %{min_size} (obecny rozmiar to %{file_size})"
8
+ file_size_not_greater_than_or_equal_to: "rozmiar pliku musi być większy lub równy %{min_size} (obecny rozmiar to %{file_size})"
9
+ file_size_not_between: "rozmiar pliku musi mieścić się w przedziale od %{min_size} do %{max_size} (obecny rozmiar to %{file_size})"
6
10
  limit_out_of_range: "ilość przekracza dopuszczalny zakres"
7
11
  image_metadata_missing: "nie jest prawidłowym obrazem"
8
12
  dimension_min_inclusion: "musi być równe lub większe od %{width} x %{height} pixeli"
@@ -2,7 +2,11 @@ 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: "tem tamanho %{file_size} e está fora da faixa de tamanho válida"
5
+ file_size_not_less_than: "o tamanho do arquivo deve ser menor que %{max_size} (o tamanho atual é %{file_size})"
6
+ file_size_not_less_than_or_equal_to: "o tamanho do arquivo deve ser menor ou igual a %{max_size} (o tamanho atual é %{file_size})"
7
+ file_size_not_greater_than: "o tamanho do arquivo deve ser maior que %{min_size} (o tamanho atual é %{file_size})"
8
+ file_size_not_greater_than_or_equal_to: "o tamanho do arquivo deve ser maior ou igual a %{min_size} (o tamanho atual é %{file_size})"
9
+ file_size_not_between: "o tamanho do arquivo deve estar entre %{min_size} e %{max_size} (o tamanho atual é %{file_size})"
6
10
  limit_out_of_range: "o número total está fora do limite"
7
11
  image_metadata_missing: "não é uma imagem válida"
8
12
  dimension_min_inclusion: "deve ser maior ou igual a %{width} x %{height} pixels"
@@ -20,3 +24,4 @@ pt-BR:
20
24
  aspect_ratio_not_landscape: "não está no formato paisagem"
21
25
  aspect_ratio_is_not: "não contém uma proporção de %{aspect_ratio}"
22
26
  aspect_ratio_unknown: "não tem uma proporção definida"
27
+ image_not_processable: "não é uma imagem válida"
@@ -2,7 +2,11 @@ ru:
2
2
  errors:
3
3
  messages:
4
4
  content_type_invalid: "имеет недопустимый тип содержимого"
5
- file_size_out_of_range: "размер %{file_size} больше требуемого"
5
+ file_size_not_less_than: "размер файла должен быть меньше %{max_size} (текущий размер %{file_size})"
6
+ file_size_not_less_than_or_equal_to: "размер файла должен быть меньше или равен %{max_size} (текущий размер %{file_size})"
7
+ file_size_not_greater_than: "размер файла должен быть больше %{min_size} (текущий размер %{file_size})"
8
+ file_size_not_greater_than_or_equal_to: "размер файла должен быть больше или равен %{min_size} (текущий размер %{file_size})"
9
+ file_size_not_between: "размер файла должен быть между %{min_size} и %{max_size} (текущий размер %{file_size})"
6
10
  limit_out_of_range: "количество файлов больше требуемого"
7
11
  image_metadata_missing: "не является допустимым изображением"
8
12
  dimension_min_inclusion: "должен быть больше или равно %{width} x %{height} пикселям"
@@ -0,0 +1,23 @@
1
+ sv:
2
+ errors:
3
+ messages:
4
+ content_type_invalid: "Har en ogiltig filtyp"
5
+ file_size_out_of_range: "storleken %{file_size} är utanför det krävda intervallet"
6
+ limit_out_of_range: "antalet filer är utanför det godkända intervallet"
7
+ image_metadata_missing: "bilden sankar metadata"
8
+ dimension_min_inclusion: "måste minst vara %{width} x %{height} pixlar"
9
+ dimension_max_inclusion: "måste vara mindre eller lika med %{width} x %{height} pixlar"
10
+ dimension_width_inclusion: "bredden är utanför %{min} till %{max} pixlar"
11
+ dimension_height_inclusion: "höjden är utanför %{min} till %{max} pixlar"
12
+ dimension_width_greater_than_or_equal_to: "bredden måste minst vara %{length} pixlar"
13
+ dimension_height_greater_than_or_equal_to: "höjden måste minst vara %{length} pixlar"
14
+ dimension_width_less_than_or_equal_to: "bredden får max vara %{length} pixlar"
15
+ dimension_height_less_than_or_equal_to: "höjden får max vara %{length} pixlar"
16
+ dimension_width_equal_to: "bredden måste vara %{length} pixlar"
17
+ dimension_height_equal_to: "höjden måste vara %{length} pixlar"
18
+ aspect_ratio_not_square: "måste vara en kvadratisk bild"
19
+ aspect_ratio_not_portrait: "måste vara en porträttorienterad bild"
20
+ aspect_ratio_not_landscape: "måste vara en landskapsorienterad bild"
21
+ aspect_ratio_is_not: "måste ha en följande aspect ratio %{aspect_ratio}"
22
+ aspect_ratio_unknown: "har en okänd aspect ratio"
23
+ image_not_processable: "är inte en giltig bild"
@@ -2,7 +2,11 @@ tr:
2
2
  errors:
3
3
  messages:
4
4
  content_type_invalid: "geçersiz dosya tipine sahip"
5
- file_size_out_of_range: "dosya boyutu %{file_size} gerekli aralık dışında"
5
+ file_size_not_less_than: "dosya boyutu %{max_size} boyutundan küçük olmalıdır (geçerli boyut %{file_size}'dir)"
6
+ file_size_not_less_than_or_equal_to: "dosya boyutu %{max_size} değerinden küçük veya ona eşit olmalıdır (geçerli boyut %{file_size}'dir)"
7
+ file_size_not_greater_than: "dosya boyutu %{min_size} boyutundan büyük olmalıdır (geçerli boyut %{file_size}'dir)"
8
+ file_size_not_greater_than_or_equal_to: "dosya boyutu %{min_size} değerinden büyük veya eşit olmalıdır (geçerli boyut %{file_size}'dir)"
9
+ file_size_not_between: "dosya boyutu %{min_size} ile %{max_size} arasında olmalıdır (geçerli boyut %{file_size}'dir)"
6
10
  limit_out_of_range: "toplam miktar aralık dışında"
7
11
  image_metadata_missing: "geçerli bir imaj değil"
8
12
  dimension_min_inclusion: "%{width} x %{height} piksele eşit ya da büyük olmalı"
@@ -2,7 +2,11 @@ uk:
2
2
  errors:
3
3
  messages:
4
4
  content_type_invalid: "має неприпустимий тип вмісту"
5
- file_size_out_of_range: "розмір %{file_size} більше необхідного"
5
+ file_size_not_less_than: "розмір файлу має бути менше %{max_size} (поточний розмір %{file_size})"
6
+ file_size_not_less_than_or_equal_to: "розмір файлу має бути меншим або дорівнювати %{max_size} (поточний розмір %{file_size})"
7
+ file_size_not_greater_than: "розмір файлу має бути більшим ніж %{min_size} (поточний розмір %{file_size})"
8
+ file_size_not_greater_than_or_equal_to: "розмір файлу має бути більшим або дорівнювати %{min_size} (поточний розмір %{file_size})"
9
+ file_size_not_between: "розмір файлу має бути від %{min_size} до %{max_size} (поточний розмір %{file_size})"
6
10
  limit_out_of_range: "кількість файлів більше необхідного"
7
11
  image_metadata_missing: "не є допустимим зображенням"
8
12
  dimension_min_inclusion: "мусить бути більше або дорівнювати %{width} x %{height} пікселям"
@@ -2,7 +2,11 @@ vi:
2
2
  errors:
3
3
  messages:
4
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"
5
+ file_size_not_less_than: "kích thước tệp phải nhỏ hơn %{max_size} (kích thước hiện tại là %{file_size})"
6
+ file_size_not_less_than_or_equal_to: "kích thước tệp phải nhỏ hơn hoặc bằng %{max_size} (kích thước hiện tại là %{file_size})"
7
+ file_size_not_greater_than: "kích thước tệp phải lớn hơn %{min_size} (kích thước hiện tại là %{file_size})"
8
+ file_size_not_greater_than_or_equal_to: "kích thước tệp phải lớn hơn hoặc bằng %{min_size} (kích thước hiện tại là %{file_size})"
9
+ file_size_not_between: "kích thước tệp phải nằm trong khoảng từ %{min_size} đến %{max_size} (kích thước hiện tại là %{file_size})"
6
10
  limit_out_of_range: "tổng số tệp vượt giới hạn"
7
11
  image_metadata_missing: "không phải là ảnh"
8
12
  dimension_min_inclusion: "phải lớn hơn hoặc bằng %{width} x %{height} pixel"
@@ -2,7 +2,11 @@ zh-CN:
2
2
  errors:
3
3
  messages:
4
4
  content_type_invalid: "文件类型错误"
5
- file_size_out_of_range: "文件大小 %{file_size} 超出限定范围"
5
+ file_size_not_less_than: "文件大小必须小于 %{max_size}(当前大小为 %{file_size})"
6
+ file_size_not_less_than_or_equal_to: "文件大小必须小于或等于 %{max_size}(当前大小为 %{file_size})"
7
+ file_size_not_greater_than: "文件大小必须大于 %{min_size}(当前大小为 %{file_size})"
8
+ file_size_not_greater_than_or_equal_to: "文件大小必须大于或等于 %{min_size}(当前大小为 %{file_size})"
9
+ file_size_not_between: "文件大小必须介于 %{min_size} 和 %{max_size} 之间(当前大小为 %{file_size})"
6
10
  limit_out_of_range: "文件数超出限定范围"
7
11
  image_metadata_missing: "不是有效的图像"
8
12
  dimension_min_inclusion: "必须大于或等于 %{width} x %{height} 像素"
@@ -5,13 +5,15 @@ require_relative 'metadata.rb'
5
5
  module ActiveStorageValidations
6
6
  class AspectRatioValidator < ActiveModel::EachValidator # :nodoc
7
7
  include OptionProcUnfolding
8
+ include ErrorHandler
8
9
 
9
10
  AVAILABLE_CHECKS = %i[with].freeze
10
11
  PRECISION = 3
11
12
 
12
13
  def check_validity!
13
- return true if AVAILABLE_CHECKS.any? { |argument| options.key?(argument) }
14
- raise ArgumentError, 'You must pass :with to the validator'
14
+ unless AVAILABLE_CHECKS.any? { |argument| options.key?(argument) }
15
+ raise ArgumentError, 'You must pass :with to the validator'
16
+ end
15
17
  end
16
18
 
17
19
  if Rails.gem_version >= Gem::Version.new('6.0.0')
@@ -53,23 +55,30 @@ module ActiveStorageValidations
53
55
 
54
56
  def is_valid?(record, attribute, metadata)
55
57
  flat_options = unfold_procs(record, self.options, AVAILABLE_CHECKS)
58
+ errors_options = initialize_error_options(options)
59
+
56
60
  if metadata[:width].to_i <= 0 || metadata[:height].to_i <= 0
57
- add_error(record, attribute, :image_metadata_missing, flat_options[:with])
61
+ errors_options[:aspect_ratio] = flat_options[:with]
62
+
63
+ add_error(record, attribute, :image_metadata_missing, **errors_options)
58
64
  return false
59
65
  end
60
66
 
61
67
  case flat_options[:with]
62
68
  when :square
63
69
  return true if metadata[:width] == metadata[:height]
64
- add_error(record, attribute, :aspect_ratio_not_square, flat_options[:with])
70
+ errors_options[:aspect_ratio] = flat_options[:with]
71
+ add_error(record, attribute, :aspect_ratio_not_square, **errors_options)
65
72
 
66
73
  when :portrait
67
74
  return true if metadata[:height] > metadata[:width]
68
- add_error(record, attribute, :aspect_ratio_not_portrait, flat_options[:with])
75
+ errors_options[:aspect_ratio] = flat_options[:with]
76
+ add_error(record, attribute, :aspect_ratio_not_portrait, **errors_options)
69
77
 
70
78
  when :landscape
71
79
  return true if metadata[:width] > metadata[:height]
72
- add_error(record, attribute, :aspect_ratio_not_landscape, flat_options[:with])
80
+ errors_options[:aspect_ratio] = flat_options[:with]
81
+ add_error(record, attribute, :aspect_ratio_not_landscape, **errors_options)
73
82
 
74
83
  else
75
84
  if flat_options[:with] =~ /is_(\d*)_(\d*)/
@@ -78,20 +87,14 @@ module ActiveStorageValidations
78
87
 
79
88
  return true if (x.to_f / y).round(PRECISION) == (metadata[:width].to_f / metadata[:height]).round(PRECISION)
80
89
 
81
- add_error(record, attribute, :aspect_ratio_is_not, "#{x}x#{y}")
90
+ errors_options[:aspect_ratio] = "#{x}x#{y}"
91
+ add_error(record, attribute, :aspect_ratio_is_not, **errors_options)
82
92
  else
83
- add_error(record, attribute, :aspect_ratio_unknown, flat_options[:with])
93
+ errors_options[:aspect_ratio] = flat_options[:with]
94
+ add_error(record, attribute, :aspect_ratio_unknown, **errors_options)
84
95
  end
85
96
  end
86
97
  false
87
98
  end
88
-
89
-
90
- def add_error(record, attribute, default_message, interpolate)
91
- message = options[:message].presence || default_message
92
- return if record.errors.added?(attribute, message)
93
- record.errors.add(attribute, message, aspect_ratio: interpolate)
94
- end
95
-
96
99
  end
97
100
  end
@@ -2,13 +2,14 @@
2
2
 
3
3
  module ActiveStorageValidations
4
4
  class AttachedValidator < ActiveModel::EachValidator # :nodoc:
5
+ include ErrorHandler
6
+
5
7
  def validate_each(record, attribute, _value)
6
8
  return if record.send(attribute).attached?
7
9
 
8
- errors_options = {}
9
- errors_options[:message] = options[:message] if options[:message].present?
10
+ errors_options = initialize_error_options(options)
10
11
 
11
- record.errors.add(attribute, :blank, **errors_options)
12
+ add_error(record, attribute, :blank, **errors_options)
12
13
  end
13
14
  end
14
15
  end
@@ -3,6 +3,7 @@
3
3
  module ActiveStorageValidations
4
4
  class ContentTypeValidator < ActiveModel::EachValidator # :nodoc:
5
5
  include OptionProcUnfolding
6
+ include ErrorHandler
6
7
 
7
8
  AVAILABLE_CHECKS = %i[with in].freeze
8
9
 
@@ -14,14 +15,14 @@ module ActiveStorageValidations
14
15
 
15
16
  files = Array.wrap(record.send(attribute))
16
17
 
17
- errors_options = { authorized_types: types_to_human_format(types) }
18
- errors_options[:message] = options[:message] if options[:message].present?
18
+ errors_options = initialize_error_options(options)
19
+ errors_options[:authorized_types] = types_to_human_format(types)
19
20
 
20
21
  files.each do |file|
21
22
  next if is_valid?(file, types)
22
23
 
23
24
  errors_options[:content_type] = content_type(file)
24
- record.errors.add(attribute, :content_type_invalid, **errors_options)
25
+ add_error(record, attribute, :content_type_invalid, **errors_options)
25
26
  break
26
27
  end
27
28
  end
@@ -5,6 +5,7 @@ require_relative 'metadata.rb'
5
5
  module ActiveStorageValidations
6
6
  class DimensionValidator < ActiveModel::EachValidator # :nodoc
7
7
  include OptionProcUnfolding
8
+ include ErrorHandler
8
9
 
9
10
  AVAILABLE_CHECKS = %i[width height min max].freeze
10
11
 
@@ -32,8 +33,9 @@ module ActiveStorageValidations
32
33
 
33
34
 
34
35
  def check_validity!
35
- return true if AVAILABLE_CHECKS.any? { |argument| options.key?(argument) }
36
- raise ArgumentError, 'You must pass either :width, :height, :min or :max to the validator'
36
+ unless AVAILABLE_CHECKS.any? { |argument| options.key?(argument) }
37
+ raise ArgumentError, 'You must pass either :width, :height, :min or :max to the validator'
38
+ end
37
39
  end
38
40
 
39
41
 
@@ -70,9 +72,11 @@ module ActiveStorageValidations
70
72
 
71
73
  def is_valid?(record, attribute, file_metadata)
72
74
  flat_options = process_options(record)
75
+ errors_options = initialize_error_options(options)
76
+
73
77
  # Validation fails unless file metadata contains valid width and height.
74
78
  if file_metadata[:width].to_i <= 0 || file_metadata[:height].to_i <= 0
75
- add_error(record, attribute, :image_metadata_missing)
79
+ add_error(record, attribute, :image_metadata_missing, **errors_options)
76
80
  return false
77
81
  end
78
82
 
@@ -82,39 +86,58 @@ module ActiveStorageValidations
82
86
  (flat_options[:width][:min] && file_metadata[:width] < flat_options[:width][:min]) ||
83
87
  (flat_options[:height][:min] && file_metadata[:height] < flat_options[:height][:min])
84
88
  )
85
- add_error(record, attribute, :dimension_min_inclusion, width: flat_options[:width][:min], height: flat_options[:height][:min])
89
+ errors_options[:width] = flat_options[:width][:min]
90
+ errors_options[:height] = flat_options[:height][:min]
91
+
92
+ add_error(record, attribute, :dimension_min_inclusion, **errors_options)
86
93
  return false
87
94
  end
88
95
  if flat_options[:max] && (
89
96
  (flat_options[:width][:max] && file_metadata[:width] > flat_options[:width][:max]) ||
90
97
  (flat_options[:height][:max] && file_metadata[:height] > flat_options[:height][:max])
91
98
  )
92
- add_error(record, attribute, :dimension_max_inclusion, width: flat_options[:width][:max], height: flat_options[:height][:max])
99
+ errors_options[:width] = flat_options[:width][:max]
100
+ errors_options[:height] = flat_options[:height][:max]
101
+
102
+ add_error(record, attribute, :dimension_max_inclusion, **errors_options)
93
103
  return false
94
104
  end
95
105
 
96
106
  # Validation based on checks :width and :height.
97
107
  else
98
108
  width_or_height_invalid = false
109
+
99
110
  [:width, :height].each do |length|
100
111
  next unless flat_options[length]
101
112
  if flat_options[length].is_a?(Hash)
102
113
  if flat_options[length][:in] && (file_metadata[length] < flat_options[length][:min] || file_metadata[length] > flat_options[length][:max])
103
- add_error(record, attribute, :"dimension_#{length}_inclusion", min: flat_options[length][:min], max: flat_options[length][:max])
114
+ error_type = :"dimension_#{length}_inclusion"
115
+ errors_options[:min] = flat_options[length][:min]
116
+ errors_options[:max] = flat_options[length][:max]
117
+
118
+ add_error(record, attribute, error_type, **errors_options)
104
119
  width_or_height_invalid = true
105
120
  else
106
121
  if flat_options[length][:min] && file_metadata[length] < flat_options[length][:min]
107
- add_error(record, attribute, :"dimension_#{length}_greater_than_or_equal_to", length: flat_options[length][:min])
122
+ error_type = :"dimension_#{length}_greater_than_or_equal_to"
123
+ errors_options[:length] = flat_options[length][:min]
124
+
125
+ add_error(record, attribute, error_type, **errors_options)
108
126
  width_or_height_invalid = true
109
- end
110
- if flat_options[length][:max] && file_metadata[length] > flat_options[length][:max]
111
- add_error(record, attribute, :"dimension_#{length}_less_than_or_equal_to", length: flat_options[length][:max])
127
+ elsif flat_options[length][:max] && file_metadata[length] > flat_options[length][:max]
128
+ error_type = :"dimension_#{length}_less_than_or_equal_to"
129
+ errors_options[:length] = flat_options[length][:max]
130
+
131
+ add_error(record, attribute, error_type, **errors_options)
112
132
  width_or_height_invalid = true
113
133
  end
114
134
  end
115
135
  else
116
136
  if file_metadata[length] != flat_options[length]
117
- add_error(record, attribute, :"dimension_#{length}_equal_to", length: flat_options[length])
137
+ error_type = :"dimension_#{length}_equal_to"
138
+ errors_options[:length] = flat_options[length]
139
+
140
+ add_error(record, attribute, error_type, **errors_options)
118
141
  width_or_height_invalid = true
119
142
  end
120
143
  end
@@ -125,12 +148,5 @@ module ActiveStorageValidations
125
148
 
126
149
  true # valid file
127
150
  end
128
-
129
- def add_error(record, attribute, default_message, **attrs)
130
- message = options[:message].presence || default_message
131
- return if record.errors.added?(attribute, message)
132
- record.errors.add(attribute, message, **attrs)
133
- end
134
-
135
151
  end
136
152
  end
@@ -0,0 +1,18 @@
1
+ module ActiveStorageValidations
2
+ module ErrorHandler
3
+
4
+ def initialize_error_options(options)
5
+ {
6
+ message: (options[:message] if options[:message].present?)
7
+ }
8
+ end
9
+
10
+ def add_error(record, attribute, default_message, **errors_options)
11
+ message = errors_options[:message].presence || default_message
12
+ return if record.errors.added?(attribute, message)
13
+
14
+ record.errors.add(attribute, message, **errors_options)
15
+ end
16
+
17
+ end
18
+ end
@@ -3,21 +3,25 @@
3
3
  module ActiveStorageValidations
4
4
  class LimitValidator < ActiveModel::EachValidator # :nodoc:
5
5
  include OptionProcUnfolding
6
+ include ErrorHandler
6
7
 
7
8
  AVAILABLE_CHECKS = %i[max min].freeze
8
9
 
9
10
  def check_validity!
10
- return true if AVAILABLE_CHECKS.any? { |argument| options.key?(argument) }
11
- raise ArgumentError, 'You must pass either :max or :min to the validator'
11
+ unless AVAILABLE_CHECKS.any? { |argument| options.key?(argument) }
12
+ raise ArgumentError, 'You must pass either :max or :min to the validator'
13
+ end
12
14
  end
13
15
 
14
16
  def validate_each(record, attribute, _)
15
17
  files = Array.wrap(record.send(attribute)).compact.uniq
16
18
  flat_options = unfold_procs(record, self.options, AVAILABLE_CHECKS)
17
- errors_options = { min: flat_options[:min], max: flat_options[:max] }
19
+ errors_options = initialize_error_options(options)
20
+ errors_options[:min] = flat_options[:min]
21
+ errors_options[:max] = flat_options[:max]
18
22
 
19
23
  return true if files_count_valid?(files.count, flat_options)
20
- record.errors.add(attribute, options[:message].presence || :limit_out_of_range, **errors_options)
24
+ add_error(record, attribute, :limit_out_of_range, **errors_options)
21
25
  end
22
26
 
23
27
  def files_count_valid?(count, flat_options)
@@ -9,12 +9,18 @@ module ActiveStorageValidations
9
9
  class AttachedValidatorMatcher
10
10
  def initialize(attribute_name)
11
11
  @attribute_name = attribute_name
12
+ @custom_message = nil
12
13
  end
13
14
 
14
15
  def description
15
16
  "validate #{@attribute_name} must be attached"
16
17
  end
17
18
 
19
+ def with_message(message)
20
+ @custom_message = message
21
+ self
22
+ end
23
+
18
24
  def matches?(subject)
19
25
  @subject = subject.is_a?(Class) ? subject.new : subject
20
26
  responds_to_methods && valid_when_attached && invalid_when_not_attached
@@ -39,7 +45,7 @@ module ActiveStorageValidations
39
45
  def valid_when_attached
40
46
  @subject.public_send(@attribute_name).attach(attachable) unless @subject.public_send(@attribute_name).attached?
41
47
  @subject.validate
42
- @subject.errors.details[@attribute_name].exclude?(error: :blank)
48
+ @subject.errors.details[@attribute_name].exclude?(error: error_message)
43
49
  end
44
50
 
45
51
  def invalid_when_not_attached
@@ -48,7 +54,11 @@ module ActiveStorageValidations
48
54
  @subject.public_send("#{@attribute_name}=", nil)
49
55
 
50
56
  @subject.validate
51
- @subject.errors.details[@attribute_name].include?(error: :blank)
57
+ @subject.errors.details[@attribute_name].include?(error: error_message)
58
+ end
59
+
60
+ def error_message
61
+ @custom_message || :blank
52
62
  end
53
63
 
54
64
  def attachable
@@ -11,6 +11,7 @@ module ActiveStorageValidations
11
11
  class ContentTypeValidatorMatcher
12
12
  def initialize(attribute_name)
13
13
  @attribute_name = attribute_name
14
+ @custom_message = nil
14
15
  end
15
16
 
16
17
  def description
@@ -27,9 +28,14 @@ module ActiveStorageValidations
27
28
  self
28
29
  end
29
30
 
31
+ def with_message(message)
32
+ @custom_message = message
33
+ self
34
+ end
35
+
30
36
  def matches?(subject)
31
37
  @subject = subject.is_a?(Class) ? subject.new : subject
32
- responds_to_methods && allowed_types_allowed? && rejected_types_rejected?
38
+ responds_to_methods && allowed_types_allowed? && rejected_types_rejected? && validate_error_message?
33
39
  end
34
40
 
35
41
  def failure_message
@@ -77,7 +83,21 @@ module ActiveStorageValidations
77
83
  def type_allowed?(type)
78
84
  @subject.public_send(@attribute_name).attach(attachment_for(type))
79
85
  @subject.validate
80
- @subject.errors.details[@attribute_name].all? { |error| error[:error] != :content_type_invalid }
86
+ @subject.errors.details[@attribute_name].none? do |error|
87
+ error[:error].to_s.include?(error_message)
88
+ end
89
+ end
90
+
91
+ def validate_error_message?
92
+ @subject.public_send(@attribute_name).attach(attachment_for('fake/fake'))
93
+ @subject.validate
94
+ @subject.errors.details[@attribute_name].all? do |error|
95
+ error[:error].to_s.include?(error_message)
96
+ end
97
+ end
98
+
99
+ def error_message
100
+ @custom_message || :content_type_invalid.to_s
81
101
  end
82
102
 
83
103
  def attachment_for(type)
@@ -11,7 +11,8 @@ module ActiveStorageValidations
11
11
  class SizeValidatorMatcher
12
12
  def initialize(attribute_name)
13
13
  @attribute_name = attribute_name
14
- @low = @high = nil
14
+ @min = @max = nil
15
+ @custom_message = nil
15
16
  end
16
17
 
17
18
  def description
@@ -19,41 +20,46 @@ module ActiveStorageValidations
19
20
  end
20
21
 
21
22
  def less_than(size)
22
- @high = size - 1.byte
23
+ @max = size - 1.byte
23
24
  self
24
25
  end
25
26
 
26
27
  def less_than_or_equal_to(size)
27
- @high = size
28
+ @max = size
28
29
  self
29
30
  end
30
31
 
31
32
  def greater_than(size)
32
- @low = size + 1.byte
33
+ @min = size + 1.byte
33
34
  self
34
35
  end
35
36
 
36
37
  def greater_than_or_equal_to(size)
37
- @low = size
38
+ @min = size
38
39
  self
39
40
  end
40
41
 
41
42
  def between(range)
42
- @low, @high = range.first, range.last
43
+ @min, @max = range.first, range.last
44
+ self
45
+ end
46
+
47
+ def with_message(message)
48
+ @custom_message = message
43
49
  self
44
50
  end
45
51
 
46
52
  def matches?(subject)
47
53
  @subject = subject.is_a?(Class) ? subject.new : subject
48
- responds_to_methods && lower_than_low? && higher_than_low? && lower_than_high? && higher_than_high?
54
+ responds_to_methods && not_lower_than_min? && higher_than_min? && lower_than_max? && not_higher_than_max?
49
55
  end
50
56
 
51
57
  def failure_message
52
- "is expected to validate file size of #{@attribute_name} to be between #{@low} and #{@high} bytes"
58
+ "is expected to validate file size of #{@attribute_name} to be between #{@min} and #{@max} bytes"
53
59
  end
54
60
 
55
61
  def failure_message_when_negated
56
- "is expected to not validate file size of #{@attribute_name} to be between #{@low} and #{@high} bytes"
62
+ "is expected to not validate file size of #{@attribute_name} to be between #{@min} and #{@max} bytes"
57
63
  end
58
64
 
59
65
  protected
@@ -64,20 +70,20 @@ module ActiveStorageValidations
64
70
  @subject.public_send(@attribute_name).respond_to?(:detach)
65
71
  end
66
72
 
67
- def lower_than_low?
68
- @low.nil? || !passes_validation_with_size(@low - 1)
73
+ def not_lower_than_min?
74
+ @min.nil? || !passes_validation_with_size(@min - 1)
69
75
  end
70
76
 
71
- def higher_than_low?
72
- @low.nil? || passes_validation_with_size(@low + 1)
77
+ def higher_than_min?
78
+ @min.nil? || passes_validation_with_size(@min + 1)
73
79
  end
74
80
 
75
- def lower_than_high?
76
- @high.nil? || @high == Float::INFINITY || passes_validation_with_size(@high - 1)
81
+ def lower_than_max?
82
+ @max.nil? || @max == Float::INFINITY || passes_validation_with_size(@max - 1)
77
83
  end
78
84
 
79
- def higher_than_high?
80
- @high.nil? || @high == Float::INFINITY || !passes_validation_with_size(@high + 1)
85
+ def not_higher_than_max?
86
+ @max.nil? || @max == Float::INFINITY || !passes_validation_with_size(@max + 1)
81
87
  end
82
88
 
83
89
  def passes_validation_with_size(new_size)
@@ -85,7 +91,10 @@ module ActiveStorageValidations
85
91
  Matchers.stub_method(io, :size, new_size) do
86
92
  @subject.public_send(@attribute_name).attach(io: io, filename: 'test.png', content_type: 'image/pg')
87
93
  @subject.validate
88
- @subject.errors.details[@attribute_name].all? { |error| error[:error] != :file_size_out_of_range }
94
+ exclude_error_message = @custom_message || "file_size_not_"
95
+ @subject.errors.details[@attribute_name].none? do |error|
96
+ error[:error].to_s.include?(exclude_error_message)
97
+ end
89
98
  end
90
99
  end
91
100
  end
@@ -5,18 +5,21 @@ require_relative 'metadata.rb'
5
5
  module ActiveStorageValidations
6
6
  class ProcessableImageValidator < ActiveModel::EachValidator # :nodoc
7
7
  include OptionProcUnfolding
8
+ include ErrorHandler
8
9
 
9
10
  if Rails.gem_version >= Gem::Version.new('6.0.0')
10
11
  def validate_each(record, attribute, _value)
11
12
  return true unless record.send(attribute).attached?
12
13
 
14
+ errors_options = initialize_error_options(options)
15
+
13
16
  changes = record.attachment_changes[attribute.to_s]
14
17
  return true if changes.blank?
15
18
 
16
19
  files = Array.wrap(changes.is_a?(ActiveStorage::Attached::Changes::CreateMany) ? changes.attachables : changes.attachable)
17
20
 
18
21
  files.each do |file|
19
- add_error(record, attribute, :image_not_processable) unless Metadata.new(file).valid?
22
+ add_error(record, attribute, :image_not_processable, **errors_options) unless Metadata.new(file).valid?
20
23
  end
21
24
  end
22
25
  else
@@ -27,17 +30,9 @@ module ActiveStorageValidations
27
30
  files = Array.wrap(record.send(attribute))
28
31
 
29
32
  files.each do |file|
30
- add_error(record, attribute, :image_not_processable) unless Metadata.new(file).valid?
33
+ add_error(record, attribute, :image_not_processable, **errors_options) unless Metadata.new(file).valid?
31
34
  end
32
35
  end
33
36
  end
34
-
35
- private
36
-
37
- def add_error(record, attribute, default_message)
38
- message = options[:message].presence || default_message
39
- return if record.errors.added?(attribute, message)
40
- record.errors.add(attribute, message)
41
- end
42
37
  end
43
38
  end
@@ -3,14 +3,16 @@
3
3
  module ActiveStorageValidations
4
4
  class SizeValidator < ActiveModel::EachValidator # :nodoc:
5
5
  include OptionProcUnfolding
6
+ include ErrorHandler
6
7
 
7
8
  delegate :number_to_human_size, to: ActiveSupport::NumberHelper
8
9
 
9
10
  AVAILABLE_CHECKS = %i[less_than less_than_or_equal_to greater_than greater_than_or_equal_to between].freeze
10
11
 
11
12
  def check_validity!
12
- return true if AVAILABLE_CHECKS.any? { |argument| options.key?(argument) }
13
- raise ArgumentError, 'You must pass either :less_than(_or_equal_to), :greater_than(_or_equal_to), or :between to the validator'
13
+ unless AVAILABLE_CHECKS.one? { |argument| options.key?(argument) }
14
+ raise ArgumentError, 'You must pass either :less_than(_or_equal_to), :greater_than(_or_equal_to), or :between to the validator'
15
+ end
14
16
  end
15
17
 
16
18
  def validate_each(record, attribute, _value)
@@ -19,8 +21,8 @@ module ActiveStorageValidations
19
21
 
20
22
  files = Array.wrap(record.send(attribute))
21
23
 
22
- errors_options = {}
23
- errors_options[:message] = options[:message] if options[:message].present?
24
+ errors_options = initialize_error_options(options)
25
+
24
26
  flat_options = unfold_procs(record, self.options, AVAILABLE_CHECKS)
25
27
 
26
28
  files.each do |file|
@@ -29,8 +31,9 @@ module ActiveStorageValidations
29
31
  errors_options[:file_size] = number_to_human_size(file.blob.byte_size)
30
32
  errors_options[:min_size] = number_to_human_size(min_size(flat_options))
31
33
  errors_options[:max_size] = number_to_human_size(max_size(flat_options))
34
+ error_type = "file_size_not_#{flat_options.keys.first}".to_sym
32
35
 
33
- record.errors.add(attribute, :file_size_out_of_range, **errors_options)
36
+ add_error(record, attribute, error_type, **errors_options)
34
37
  break
35
38
  end
36
39
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveStorageValidations
4
- VERSION = '1.0.4'
4
+ VERSION = '1.1.0'
5
5
  end
@@ -1,8 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'active_model'
4
+
3
5
  require 'active_storage_validations/railtie'
4
6
  require 'active_storage_validations/engine'
5
7
  require 'active_storage_validations/option_proc_unfolding'
8
+ require 'active_storage_validations/error_handler'
6
9
  require 'active_storage_validations/attached_validator'
7
10
  require 'active_storage_validations/content_type_validator'
8
11
  require 'active_storage_validations/size_validator'
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: 1.0.4
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Igor Kasyanchuk
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-06-10 00:00:00.000000000 Z
11
+ date: 2023-10-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activejob
@@ -212,6 +212,7 @@ files:
212
212
  - config/locales/pl.yml
213
213
  - config/locales/pt-BR.yml
214
214
  - config/locales/ru.yml
215
+ - config/locales/sv.yml
215
216
  - config/locales/tr.yml
216
217
  - config/locales/uk.yml
217
218
  - config/locales/vi.yml
@@ -222,6 +223,7 @@ files:
222
223
  - lib/active_storage_validations/content_type_validator.rb
223
224
  - lib/active_storage_validations/dimension_validator.rb
224
225
  - lib/active_storage_validations/engine.rb
226
+ - lib/active_storage_validations/error_handler.rb
225
227
  - lib/active_storage_validations/limit_validator.rb
226
228
  - lib/active_storage_validations/matchers.rb
227
229
  - lib/active_storage_validations/matchers/attached_validator_matcher.rb
@@ -254,7 +256,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
254
256
  - !ruby/object:Gem::Version
255
257
  version: '0'
256
258
  requirements: []
257
- rubygems_version: 3.4.13
259
+ rubygems_version: 3.4.10
258
260
  signing_key:
259
261
  specification_version: 4
260
262
  summary: Validations for Active Storage