active_storage_validations 1.0.4 → 1.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +51 -7
- data/config/locales/de.yml +5 -1
- data/config/locales/en.yml +5 -1
- data/config/locales/es.yml +5 -1
- data/config/locales/fr.yml +5 -1
- data/config/locales/it.yml +5 -1
- data/config/locales/ja.yml +5 -1
- data/config/locales/nl.yml +5 -1
- data/config/locales/pl.yml +5 -1
- data/config/locales/pt-BR.yml +6 -1
- data/config/locales/ru.yml +5 -1
- data/config/locales/sv.yml +23 -0
- data/config/locales/tr.yml +5 -1
- data/config/locales/uk.yml +5 -1
- data/config/locales/vi.yml +5 -1
- data/config/locales/zh-CN.yml +5 -1
- data/lib/active_storage_validations/aspect_ratio_validator.rb +19 -16
- data/lib/active_storage_validations/attached_validator.rb +4 -3
- data/lib/active_storage_validations/content_type_validator.rb +4 -3
- data/lib/active_storage_validations/dimension_validator.rb +34 -18
- data/lib/active_storage_validations/error_handler.rb +18 -0
- data/lib/active_storage_validations/limit_validator.rb +8 -4
- data/lib/active_storage_validations/matchers/attached_validator_matcher.rb +12 -2
- data/lib/active_storage_validations/matchers/content_type_validator_matcher.rb +24 -2
- data/lib/active_storage_validations/matchers/size_validator_matcher.rb +27 -18
- data/lib/active_storage_validations/processable_image_validator.rb +5 -10
- data/lib/active_storage_validations/size_validator.rb +8 -5
- data/lib/active_storage_validations/version.rb +1 -1
- data/lib/active_storage_validations.rb +3 -0
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3b512ecda0ff1fa0f06649f78b7b4f58433ca7f108abd729ce08cd0eea2b1baf
|
4
|
+
data.tar.gz: 1ef72d050d31ed0d4052672370849c5d66538df5b06e5a477ebc3575fc110e40
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dc0392b8725f2a567df3f99b61c5053ab0870e877ba16f3085871842a70ca7f5db328b63b3275912017831d4ed29697a66106cdad4e7cfbb779a1985b7d20488
|
7
|
+
data.tar.gz: 8a6883ac4f1cbf0e703c41d1e8ddf6136397fb3973997cc37c83aef3f0456ab5278b5475518ce3ddb8a776a41c8e8f7774160850ddcb49b5ece6e9c846cab8db
|
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
|
-
|
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
|
-
|
176
|
-
|
177
|
-
|
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
|
-
|
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
|
|
data/config/locales/de.yml
CHANGED
@@ -2,7 +2,11 @@ de:
|
|
2
2
|
errors:
|
3
3
|
messages:
|
4
4
|
content_type_invalid: "hat einen ungültigen Dateityp"
|
5
|
-
|
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"
|
data/config/locales/en.yml
CHANGED
@@ -2,7 +2,11 @@ en:
|
|
2
2
|
errors:
|
3
3
|
messages:
|
4
4
|
content_type_invalid: "has an invalid content type"
|
5
|
-
|
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"
|
data/config/locales/es.yml
CHANGED
@@ -2,7 +2,11 @@ es:
|
|
2
2
|
errors:
|
3
3
|
messages:
|
4
4
|
content_type_invalid: "tiene un tipo de contenido inválido"
|
5
|
-
|
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"
|
data/config/locales/fr.yml
CHANGED
@@ -2,7 +2,11 @@ fr:
|
|
2
2
|
errors:
|
3
3
|
messages:
|
4
4
|
content_type_invalid: "a un type de contenu non valide"
|
5
|
-
|
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"
|
data/config/locales/it.yml
CHANGED
@@ -2,7 +2,11 @@ it:
|
|
2
2
|
errors:
|
3
3
|
messages:
|
4
4
|
content_type_invalid: "ha un tipo di contenuto non valido"
|
5
|
-
|
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"
|
data/config/locales/ja.yml
CHANGED
@@ -2,7 +2,11 @@ ja:
|
|
2
2
|
errors:
|
3
3
|
messages:
|
4
4
|
content_type_invalid: "のContent Typeが不正です"
|
5
|
-
|
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} ピクセル以上の大きさにしてください"
|
data/config/locales/nl.yml
CHANGED
@@ -2,7 +2,11 @@ nl:
|
|
2
2
|
errors:
|
3
3
|
messages:
|
4
4
|
content_type_invalid: "heeft een ongeldig inhoudstype"
|
5
|
-
|
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"
|
data/config/locales/pl.yml
CHANGED
@@ -2,7 +2,11 @@ pl:
|
|
2
2
|
errors:
|
3
3
|
messages:
|
4
4
|
content_type_invalid: "jest nieprawidłowego typu"
|
5
|
-
|
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"
|
data/config/locales/pt-BR.yml
CHANGED
@@ -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
|
-
|
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"
|
data/config/locales/ru.yml
CHANGED
@@ -2,7 +2,11 @@ ru:
|
|
2
2
|
errors:
|
3
3
|
messages:
|
4
4
|
content_type_invalid: "имеет недопустимый тип содержимого"
|
5
|
-
|
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"
|
data/config/locales/tr.yml
CHANGED
@@ -2,7 +2,11 @@ tr:
|
|
2
2
|
errors:
|
3
3
|
messages:
|
4
4
|
content_type_invalid: "geçersiz dosya tipine sahip"
|
5
|
-
|
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ı"
|
data/config/locales/uk.yml
CHANGED
@@ -2,7 +2,11 @@ uk:
|
|
2
2
|
errors:
|
3
3
|
messages:
|
4
4
|
content_type_invalid: "має неприпустимий тип вмісту"
|
5
|
-
|
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} пікселям"
|
data/config/locales/vi.yml
CHANGED
@@ -2,7 +2,11 @@ vi:
|
|
2
2
|
errors:
|
3
3
|
messages:
|
4
4
|
content_type_invalid: "tệp không hợp lệ"
|
5
|
-
|
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"
|
data/config/locales/zh-CN.yml
CHANGED
@@ -2,7 +2,11 @@ zh-CN:
|
|
2
2
|
errors:
|
3
3
|
messages:
|
4
4
|
content_type_invalid: "文件类型错误"
|
5
|
-
|
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
|
-
|
14
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
90
|
+
errors_options[:aspect_ratio] = "#{x}x#{y}"
|
91
|
+
add_error(record, attribute, :aspect_ratio_is_not, **errors_options)
|
82
92
|
else
|
83
|
-
|
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
|
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 =
|
18
|
-
errors_options[:
|
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
|
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
|
-
|
36
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
110
|
-
|
111
|
-
|
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
|
-
|
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
|
-
|
11
|
-
|
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 =
|
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
|
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:
|
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:
|
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_custom_message?
|
33
39
|
end
|
34
40
|
|
35
41
|
def failure_message
|
@@ -77,7 +83,23 @@ 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].
|
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_custom_message?
|
92
|
+
return true unless @custom_message
|
93
|
+
|
94
|
+
@subject.public_send(@attribute_name).attach(attachment_for('fake/fake'))
|
95
|
+
@subject.validate
|
96
|
+
@subject.errors.details[@attribute_name].select{|error| error[:content_type]}.all? do |error|
|
97
|
+
error[:error].to_s.include?(error_message)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def error_message
|
102
|
+
@custom_message || :content_type_invalid.to_s
|
81
103
|
end
|
82
104
|
|
83
105
|
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
|
-
@
|
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
|
-
@
|
23
|
+
@max = size - 1.byte
|
23
24
|
self
|
24
25
|
end
|
25
26
|
|
26
27
|
def less_than_or_equal_to(size)
|
27
|
-
@
|
28
|
+
@max = size
|
28
29
|
self
|
29
30
|
end
|
30
31
|
|
31
32
|
def greater_than(size)
|
32
|
-
@
|
33
|
+
@min = size + 1.byte
|
33
34
|
self
|
34
35
|
end
|
35
36
|
|
36
37
|
def greater_than_or_equal_to(size)
|
37
|
-
@
|
38
|
+
@min = size
|
38
39
|
self
|
39
40
|
end
|
40
41
|
|
41
42
|
def between(range)
|
42
|
-
@
|
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 &&
|
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 #{@
|
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 #{@
|
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
|
68
|
-
@
|
73
|
+
def not_lower_than_min?
|
74
|
+
@min.nil? || !passes_validation_with_size(@min - 1)
|
69
75
|
end
|
70
76
|
|
71
|
-
def
|
72
|
-
@
|
77
|
+
def higher_than_min?
|
78
|
+
@min.nil? || passes_validation_with_size(@min + 1)
|
73
79
|
end
|
74
80
|
|
75
|
-
def
|
76
|
-
@
|
81
|
+
def lower_than_max?
|
82
|
+
@max.nil? || @max == Float::INFINITY || passes_validation_with_size(@max - 1)
|
77
83
|
end
|
78
84
|
|
79
|
-
def
|
80
|
-
@
|
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
|
-
|
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
|
-
|
13
|
-
|
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
|
-
|
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
|
36
|
+
add_error(record, attribute, error_type, **errors_options)
|
34
37
|
break
|
35
38
|
end
|
36
39
|
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.
|
4
|
+
version: 1.1.1
|
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-
|
11
|
+
date: 2023-10-26 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.
|
259
|
+
rubygems_version: 3.4.10
|
258
260
|
signing_key:
|
259
261
|
specification_version: 4
|
260
262
|
summary: Validations for Active Storage
|