active_storage_validations 1.0.4 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +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 +22 -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: f41ec7bce11523af0deebbac7aac427c19a0c5f9788c3719ff94122468781a79
|
4
|
+
data.tar.gz: aef955507fb8c8b3a42a27820ea213347f03c49373eef27b44a99e764456b77d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
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_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].
|
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
|
-
@
|
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.0
|
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-
|
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.
|
259
|
+
rubygems_version: 3.4.10
|
258
260
|
signing_key:
|
259
261
|
specification_version: 4
|
260
262
|
summary: Validations for Active Storage
|