active_storage_validations 0.8.6 → 0.9.1
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 +110 -14
- data/config/locales/de.yml +8 -8
- data/config/locales/es.yml +22 -0
- data/config/locales/ja.yml +22 -0
- data/config/locales/nl.yml +22 -0
- data/config/locales/tr.yml +22 -0
- data/config/locales/uk.yml +19 -19
- data/lib/active_storage_validations/content_type_validator.rb +1 -1
- data/lib/active_storage_validations/dimension_validator.rb +1 -1
- data/lib/active_storage_validations/limit_validator.rb +1 -1
- data/lib/active_storage_validations/matchers.rb +43 -0
- data/lib/active_storage_validations/matchers/attached_validator_matcher.rb +59 -0
- data/lib/active_storage_validations/matchers/content_type_validator_matcher.rb +101 -0
- data/lib/active_storage_validations/matchers/dimension_validator_matcher.rb +145 -0
- data/lib/active_storage_validations/matchers/size_validator_matcher.rb +93 -0
- data/lib/active_storage_validations/metadata.rb +14 -3
- data/lib/active_storage_validations/size_validator.rb +1 -1
- data/lib/active_storage_validations/version.rb +1 -1
- metadata +12 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0475512c246a633adcc226c575f66826ffa09df688fda330f2b862d7229a3e3a
|
4
|
+
data.tar.gz: c52cbf3aa8527ddfc7e17f8619d63f1f3b008360e969f054a129d8e0f6af2e51
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f472fa75d9d021f8ab55bff5dd900d738449884f9bf6ee72d953bb34c988acf01904c29dca7586f5d82ad192b9914bfd9e6f365d413615ef1b3aa18b9635cbb1
|
7
|
+
data.tar.gz: 8f1b3da90613ff72ab85aaa6faf6fe7403b132e1806c2e4f60156cf95d9f9dfd1dac20d950c7eb0cda64229427deb51d1ce2e4b1742020040c78853c8cdc1bba
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Active Storage Validations
|
2
2
|
|
3
|
-
If you are using `active_storage` gem and you want to add simple validations for it, like presence or content_type you need to write a custom
|
3
|
+
If you are using `active_storage` gem and you want to add simple validations for it, like presence or content_type you need to write a custom validation method.
|
4
4
|
|
5
5
|
This gems doing it for you. Just use `attached: true` or `content_type: 'image/png'` validation.
|
6
6
|
|
@@ -117,7 +117,7 @@ end
|
|
117
117
|
|
118
118
|
## Internationalization (I18n)
|
119
119
|
|
120
|
-
Active Storage Validations
|
120
|
+
Active Storage Validations uses I18n for error messages. For this, add these keys in your translation file:
|
121
121
|
|
122
122
|
```yml
|
123
123
|
en:
|
@@ -137,19 +137,18 @@ en:
|
|
137
137
|
dimension_height_less_than_or_equal_to: "height must be less than or equal to %{length} pixel."
|
138
138
|
dimension_width_equal_to: "width must be equal to %{length} pixel."
|
139
139
|
dimension_height_equal_to: "height must be equal to %{length} pixel."
|
140
|
-
aspect_ratio_not_square: "
|
141
|
-
aspect_ratio_not_portrait: "
|
142
|
-
aspect_ratio_not_landscape: "
|
143
|
-
aspect_ratio_is_not: "
|
140
|
+
aspect_ratio_not_square: "must be a square image"
|
141
|
+
aspect_ratio_not_portrait: "must be a portrait image"
|
142
|
+
aspect_ratio_not_landscape: "must be a landscape image"
|
143
|
+
aspect_ratio_is_not: "must have an aspect ratio of %{aspect_ratio}"
|
144
144
|
aspect_ratio_unknown: "has an unknown aspect ratio"
|
145
|
-
|
146
145
|
```
|
147
146
|
|
148
|
-
In some cases Active Storage Validations provides variables to help you customize messages:
|
147
|
+
In some cases, Active Storage Validations provides variables to help you customize messages:
|
149
148
|
|
150
|
-
The "content_type_invalid" key has two variables that you can use, a variable named "content_type" containing the content type of the send file and a variable named "
|
149
|
+
The "content_type_invalid" key has two variables that you can use, a variable named "content_type" containing the content type of the send file and a variable named "authorized_types" containing the list of authorized content types.
|
151
150
|
|
152
|
-
|
151
|
+
The variables are not used by default to leave the choice to the user.
|
153
152
|
|
154
153
|
For example :
|
155
154
|
|
@@ -189,20 +188,106 @@ Very simple example of validation with file attached, content type check and cus
|
|
189
188
|
|
190
189
|
[](https://raw.githubusercontent.com/igorkasyanchuk/active_storage_validations/master/docs/preview.png)
|
191
190
|
|
191
|
+
## Test matchers
|
192
|
+
Provides RSpec-compatible and Minitest-compatible matchers for testing the validators.
|
193
|
+
|
194
|
+
### RSpec
|
195
|
+
|
196
|
+
In `spec_helper.rb`, you'll need to require the matchers:
|
197
|
+
|
198
|
+
```ruby
|
199
|
+
require 'active_storage_validations/matchers'
|
200
|
+
```
|
201
|
+
|
202
|
+
And _include_ the module:
|
203
|
+
|
204
|
+
```ruby
|
205
|
+
RSpec.configure do |config|
|
206
|
+
config.include ActiveStorageValidations::Matchers
|
207
|
+
end
|
208
|
+
```
|
209
|
+
|
210
|
+
Example (Note that the options are chainable):
|
211
|
+
|
212
|
+
```ruby
|
213
|
+
describe User do
|
214
|
+
it { is_expected.to validate_attached_of(:avatar) }
|
215
|
+
|
216
|
+
it { is_expected.to validate_content_type_of(:avatar).allowing('image/png', 'image/gif') }
|
217
|
+
it { is_expected.to validate_content_type_of(:avatar).rejecting('text/plain', 'text/xml') }
|
218
|
+
|
219
|
+
it { is_expected.to validate_dimensions_of(:avatar).width(250) }
|
220
|
+
it { is_expected.to validate_dimensions_of(:avatar).height(200) }
|
221
|
+
it { is_expected.to validate_dimensions_of(:avatar).width_min(200) }
|
222
|
+
it { is_expected.to validate_dimensions_of(:avatar).width_max(500) }
|
223
|
+
it { is_expected.to validate_dimensions_of(:avatar).height_min(100) }
|
224
|
+
it { is_expected.to validate_dimensions_of(:avatar).height_max(300) }
|
225
|
+
it { is_expected.to validate_dimensions_of(:avatar).width_between(200..500) }
|
226
|
+
it { is_expected.to validate_dimensions_of(:avatar).height_between(100..300) }
|
227
|
+
|
228
|
+
it { is_expected.to validate_size_of(:avatar).less_than(50.kilobytes) }
|
229
|
+
it { is_expected.to validate_size_of(:avatar).less_than_or_equal_to(50.kilobytes) }
|
230
|
+
it { is_expected.to validate_size_of(:avatar).greater_than(1.kilobyte) }
|
231
|
+
it { is_expected.to validate_size_of(:avatar).greater_than_or_equal_to(1.kilobyte) }
|
232
|
+
it { is_expected.to validate_size_of(:avatar).between(100..500.kilobytes) }
|
233
|
+
end
|
234
|
+
```
|
235
|
+
|
236
|
+
### Minitest
|
237
|
+
To use the following syntax, make sure you have the [shoulda-context](https://github.com/thoughtbot/shoulda-context) gem up and running. To make use of the matchers you need to require the matchers:
|
238
|
+
|
239
|
+
```ruby
|
240
|
+
require 'active_storage_validations/matchers'
|
241
|
+
```
|
242
|
+
|
243
|
+
And _extend_ the module:
|
244
|
+
|
245
|
+
```ruby
|
246
|
+
class ActiveSupport::TestCase
|
247
|
+
extend ActiveStorageValidations::Matchers
|
248
|
+
end
|
249
|
+
```
|
250
|
+
|
251
|
+
Example (Note that the options are chainable):
|
252
|
+
|
253
|
+
```ruby
|
254
|
+
class UserTest < ActiveSupport::TestCase
|
255
|
+
should validate_attached_of(:avatar)
|
256
|
+
|
257
|
+
should validate_content_type_of(:avatar).allowing('image/png', 'image/gif')
|
258
|
+
should validate_content_type_of(:avatar).rejecting('text/plain', 'text/xml')
|
259
|
+
|
260
|
+
should validate_dimensions_of(:avatar).width(250)
|
261
|
+
should validate_dimensions_of(:avatar).height(200)
|
262
|
+
should validate_dimensions_of(:avatar).width_min(200)
|
263
|
+
should validate_dimensions_of(:avatar).width_max(500)
|
264
|
+
should validate_dimensions_of(:avatar).height_min(100)
|
265
|
+
should validate_dimensions_of(:avatar).height_max(300)
|
266
|
+
should validate_dimensions_of(:avatar).width_between(200..500)
|
267
|
+
should validate_dimensions_of(:avatar).height_between(100..300)
|
268
|
+
|
269
|
+
should validate_size_of(:avatar).less_than(50.kilobytes)
|
270
|
+
should validate_size_of(:avatar).less_than_or_equal_to(50.kilobytes)
|
271
|
+
should validate_size_of(:avatar).greater_than(1.kilobyte)
|
272
|
+
should validate_size_of(:avatar).greater_than_or_equal_to(1.kilobyte)
|
273
|
+
should validate_size_of(:avatar).between(100..500.kilobytes)
|
274
|
+
end
|
275
|
+
```
|
276
|
+
|
192
277
|
## Todo
|
193
278
|
|
194
279
|
* verify with remote storages (s3, etc)
|
195
280
|
* verify how it works with direct upload
|
196
281
|
* better error message when content_size is invalid
|
197
282
|
* add more translations
|
198
|
-
* add aspect ratio validation
|
199
283
|
|
200
284
|
## Tests & Contributing
|
201
285
|
|
202
286
|
To run tests in root folder of gem:
|
203
287
|
|
204
288
|
* `BUNDLE_GEMFILE=gemfiles/rails_5_2.gemfile bundle exec rake test` to run for Rails 5.2
|
205
|
-
* `BUNDLE_GEMFILE=gemfiles/
|
289
|
+
* `BUNDLE_GEMFILE=gemfiles/rails_6_0.gemfile bundle exec rake test` to run for Rails 6.0
|
290
|
+
* `BUNDLE_GEMFILE=gemfiles/rails_6_1.gemfile bundle exec rake test` to run for Rails 6.1 (TESTS ARE NOT READY, migration in DB is needed for specs)
|
206
291
|
|
207
292
|
To play with app `cd test/dummy` and `rails s -b 0.0.0.0` (before `rails db:migrate`).
|
208
293
|
|
@@ -210,12 +295,13 @@ To play with app `cd test/dummy` and `rails s -b 0.0.0.0` (before `rails db:migr
|
|
210
295
|
|
211
296
|
- There is an issue in Rails which it possible to get if you have added a validation and generating for example an image preview of attachments. It can be fixed with this:
|
212
297
|
|
213
|
-
```
|
298
|
+
```erb
|
214
299
|
<% if @user.avatar.attached? && @user.avatar.attachment.blob.present? && @user.avatar.attachment.blob.persisted? %>
|
215
300
|
<%= image_tag @user.avatar %>
|
216
301
|
<% end %>
|
217
302
|
```
|
218
|
-
|
303
|
+
|
304
|
+
This is a Rails issue, and is fixed in Rails 6.
|
219
305
|
|
220
306
|
## Contributing
|
221
307
|
You are welcome to contribute.
|
@@ -240,6 +326,16 @@ You are welcome to contribute.
|
|
240
326
|
- https://github.com/UICJohn
|
241
327
|
- https://github.com/giovannibonetti
|
242
328
|
- https://github.com/dlepage
|
329
|
+
- https://github.com/StefSchenkelaars
|
330
|
+
- https://github.com/willnet
|
331
|
+
- https://github.com/mohanklein
|
332
|
+
- https://github.com/High5Apps
|
333
|
+
- https://github.com/mschnitzer
|
334
|
+
- https://github.com/sinankeskin
|
335
|
+
- https://github.com/alejandrodevs
|
336
|
+
- https://github.com/molfar
|
337
|
+
- https://github.com/connorshea
|
338
|
+
- https://github.com/yshmarov
|
243
339
|
|
244
340
|
## License
|
245
341
|
|
data/config/locales/de.yml
CHANGED
@@ -2,16 +2,16 @@ de:
|
|
2
2
|
errors:
|
3
3
|
messages:
|
4
4
|
content_type_invalid: "hat einen ungültigen Dateityp"
|
5
|
-
file_size_out_of_range: "Dateigröße
|
5
|
+
file_size_out_of_range: "Dateigröße %{file_size} liegt nicht im erlaubten Bereich"
|
6
6
|
limit_out_of_range: "Anzahl ist außerhalb des gültigen Bereichs"
|
7
|
-
image_metadata_missing: "ist
|
7
|
+
image_metadata_missing: "ist kein gültiges Bild"
|
8
8
|
dimension_min_inclusion: "muss größer oder gleich %{width} x %{height} Pixel sein"
|
9
9
|
dimension_max_inclusion: "muss kleiner oder gleich %{width} x %{height} Pixel sein"
|
10
|
-
dimension_width_inclusion: "
|
11
|
-
dimension_height_inclusion: "
|
12
|
-
dimension_width_greater_than_or_equal_to: "
|
13
|
-
dimension_height_greater_than_or_equal_to: "
|
10
|
+
dimension_width_inclusion: "Bildbreite muss zwischen %{min} und %{max} Pixel liegen"
|
11
|
+
dimension_height_inclusion: "Bildhöhe muss zwischen %{min} und %{max} Pixel liegen"
|
12
|
+
dimension_width_greater_than_or_equal_to: "Bildbreite muss größer oder gleich %{length} Pixel sein"
|
13
|
+
dimension_height_greater_than_or_equal_to: "Bildhöhe muss größer oder gleich %{length} Pixel sein"
|
14
14
|
dimension_width_less_than_or_equal_to: "Breite muss kleiner oder gleich %{length} Pixel sein"
|
15
15
|
dimension_height_less_than_or_equal_to: "Höhe muss kleiner oder gleich %{length} Pixel sein"
|
16
|
-
dimension_width_equal_to: "
|
17
|
-
dimension_height_equal_to: "
|
16
|
+
dimension_width_equal_to: "Bildbreite muss genau %{length} Pixel sein"
|
17
|
+
dimension_height_equal_to: "Bildhöhe muss genau %{length} Pixel sein"
|
@@ -0,0 +1,22 @@
|
|
1
|
+
es:
|
2
|
+
errors:
|
3
|
+
messages:
|
4
|
+
content_type_invalid: "tiene un tipo de contenido inválido"
|
5
|
+
file_size_out_of_range: "tamaño %{file_size} no está entre el rango requerido"
|
6
|
+
limit_out_of_range: "el número total está fuera de rango"
|
7
|
+
image_metadata_missing: "no es una imagen válida"
|
8
|
+
dimension_min_inclusion: "debe ser mayor o igual a %{width} x %{height} pixel"
|
9
|
+
dimension_max_inclusion: "debe ser menor o igual a %{width} x %{height} pixel"
|
10
|
+
dimension_width_inclusion: "el ancho no se incluye entre %{min} y %{max} pixel"
|
11
|
+
dimension_height_inclusion: "la altura no se incluye entre %{min} y %{max} pixel"
|
12
|
+
dimension_width_greater_than_or_equal_to: "el ancho debe ser mayor o igual a %{length} pixel"
|
13
|
+
dimension_height_greater_than_or_equal_to: "la altura debe ser mayor o igual a %{length} pixel"
|
14
|
+
dimension_width_less_than_or_equal_to: "el ancho debe ser menor o igual a %{length} pixel"
|
15
|
+
dimension_height_less_than_or_equal_to: "la altura debe ser menor o igual a %{length} pixel"
|
16
|
+
dimension_width_equal_to: "el ancho debe ser igual a %{length} pixel"
|
17
|
+
dimension_height_equal_to: "la altura debe ser igual a %{length} pixel"
|
18
|
+
aspect_ratio_not_square: "debe ser una imagen cuadrada"
|
19
|
+
aspect_ratio_not_portrait: "debe ser una imagen de retrato"
|
20
|
+
aspect_ratio_not_landscape: "debe ser una imagen de paisaje"
|
21
|
+
aspect_ratio_is_not: "debe tener una relación de aspecto de %{aspect_ratio}"
|
22
|
+
aspect_ratio_unknown: "tiene una relación de aspecto desconocida"
|
@@ -0,0 +1,22 @@
|
|
1
|
+
ja:
|
2
|
+
errors:
|
3
|
+
messages:
|
4
|
+
content_type_invalid: "のContent Typeが不正です"
|
5
|
+
file_size_out_of_range: "の容量 %{file_size} が許容範囲外です"
|
6
|
+
limit_out_of_range: "の数が許容範囲外です"
|
7
|
+
image_metadata_missing: "は不正な画像です"
|
8
|
+
dimension_min_inclusion: "は %{width} x %{height} ピクセル以上の大きさにしてください"
|
9
|
+
dimension_max_inclusion: "は %{width} x %{height} ピクセル以下の大きさにしてください"
|
10
|
+
dimension_width_inclusion: "の横幅は %{min} ピクセル以上 %{max} ピクセル以下にしてください"
|
11
|
+
dimension_height_inclusion: "の縦幅は %{min} ピクセル以上 %{max} ピクセル以下にしてください"
|
12
|
+
dimension_width_greater_than_or_equal_to: "の横幅は %{length} ピクセル以上にしてください"
|
13
|
+
dimension_height_greater_than_or_equal_to: "の縦幅は %{length} ピクセル以上にしてください"
|
14
|
+
dimension_width_less_than_or_equal_to: "の横幅は %{length} ピクセル以下にしてください"
|
15
|
+
dimension_height_less_than_or_equal_to: "の縦幅は %{length} ピクセル以下にしてください"
|
16
|
+
dimension_width_equal_to: "の横幅は %{length} ピクセルにしてください"
|
17
|
+
dimension_height_equal_to: "の縦幅は %{length} ピクセルにしてください"
|
18
|
+
aspect_ratio_not_square: "は正方形にしてください"
|
19
|
+
aspect_ratio_not_portrait: "は縦長にしてください"
|
20
|
+
aspect_ratio_not_landscape: "は横長にしてください"
|
21
|
+
aspect_ratio_is_not: "のアスペクト比は %{aspect_ratio} にしてください"
|
22
|
+
aspect_ratio_unknown: "のアスペクト比を取得できませんでした"
|
@@ -0,0 +1,22 @@
|
|
1
|
+
nl:
|
2
|
+
errors:
|
3
|
+
messages:
|
4
|
+
content_type_invalid: "heeft een ongeldig inhoudstype"
|
5
|
+
file_size_out_of_range: "bestandsgrootte %{file_size} valt niet tussen het vereiste bereik"
|
6
|
+
limit_out_of_range: "totaal aantal valt buiten het vereiste bereik"
|
7
|
+
image_metadata_missing: "is geen geldige afbeelding"
|
8
|
+
dimension_min_inclusion: "moet groter of gelijk zijn aan %{width} x %{height} pixels"
|
9
|
+
dimension_max_inclusion: "moet kleiner of gelijk zijn aan %{width} x %{height} pixels"
|
10
|
+
dimension_width_inclusion: "breedte niet tussen de %{min} en %{max} pixels"
|
11
|
+
dimension_height_inclusion: "hoogte niet tussen de %{min} en %{max} pixels"
|
12
|
+
dimension_width_greater_than_or_equal_to: "breedte moet groter of gelijk zijn aan %{length} pixels"
|
13
|
+
dimension_height_greater_than_or_equal_to: "hoogte moet groter of gelijk zijn aan %{length} pixels"
|
14
|
+
dimension_width_less_than_or_equal_to: "breedte moet kleiner of gelijk zijn aan %{length} pixels"
|
15
|
+
dimension_height_less_than_or_equal_to: "hoogte moet kleiner of gelijk zijn aan %{length} pixels"
|
16
|
+
dimension_width_equal_to: "breedte moet gelijk zijn aan %{length} pixels"
|
17
|
+
dimension_height_equal_to: "hoogte moet gelijk zijn aan %{length} pixels"
|
18
|
+
aspect_ratio_not_square: "moet een vierkante afbeelding zijn"
|
19
|
+
aspect_ratio_not_portrait: "moet een staande afbeelding zijn"
|
20
|
+
aspect_ratio_not_landscape: "moet een liggende afbeelding zijn"
|
21
|
+
aspect_ratio_is_not: "moet een beeldverhouding hebben van %{aspect_ratio}"
|
22
|
+
aspect_ratio_unknown: "heeft een onbekende beeldverhouding"
|
@@ -0,0 +1,22 @@
|
|
1
|
+
tr:
|
2
|
+
errors:
|
3
|
+
messages:
|
4
|
+
content_type_invalid: "geçersiz dosya tipine sahip"
|
5
|
+
file_size_out_of_range: "dosya boyutu %{file_size} gerekli aralık dışında"
|
6
|
+
limit_out_of_range: "toplam miktar aralık dışında"
|
7
|
+
image_metadata_missing: "geçerli bir imaj değil"
|
8
|
+
dimension_min_inclusion: "%{width} x %{height} piksele eşit ya da büyük olmalı"
|
9
|
+
dimension_max_inclusion: "%{width} x %{height} piksele eşit ya da küçük olmalı"
|
10
|
+
dimension_width_inclusion: "en %{min} ve %{max} piksel aralığı dışında"
|
11
|
+
dimension_height_inclusion: "boy %{min} ve %{max} piksel aralığı dışında"
|
12
|
+
dimension_width_greater_than_or_equal_to: "en %{length} piksele eşit ya da büyük olmalı"
|
13
|
+
dimension_height_greater_than_or_equal_to: "boy %{length} piksele eşit ya da büyük olmalı"
|
14
|
+
dimension_width_less_than_or_equal_to: "en %{length} piksele eşit ya da küçük olmalı"
|
15
|
+
dimension_height_less_than_or_equal_to: "boy %{length} piksele eşit ya da küçük olmalı"
|
16
|
+
dimension_width_equal_to: "en %{length} piksele eşit olmalı"
|
17
|
+
dimension_height_equal_to: "boy %{length} piksele eşit olmalı"
|
18
|
+
aspect_ratio_not_square: "kare bir imaj olmalı"
|
19
|
+
aspect_ratio_not_portrait: "dikey bir imaj olmalı"
|
20
|
+
aspect_ratio_not_landscape: "yatay bir imaj olmalı"
|
21
|
+
aspect_ratio_is_not: "%{aspect_ratio} en boy oranına sahip olmalı"
|
22
|
+
aspect_ratio_unknown: "bilinmeyen en boy oranı"
|
data/config/locales/uk.yml
CHANGED
@@ -1,22 +1,22 @@
|
|
1
1
|
uk:
|
2
2
|
errors:
|
3
3
|
messages:
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
4
|
+
content_type_invalid: "має неприпустимий тип вмісту"
|
5
|
+
file_size_out_of_range: "розмір %{file_size} більше необхідного"
|
6
|
+
limit_out_of_range: "кількість файлів більше необхідного"
|
7
|
+
image_metadata_missing: "не є допустимим зображенням"
|
8
|
+
dimension_min_inclusion: "мусить бути більше або дорівнювати %{width} x %{height} пікселям"
|
9
|
+
dimension_max_inclusion: "мусить бути менше або дорівнювати %{width} x %{height} пікселям"
|
10
|
+
dimension_width_inclusion: "ширина не включена між %{min} і %{max} пікселям"
|
11
|
+
dimension_height_inclusion: "висота не включена між %{min} і %{max} пікселям"
|
12
|
+
dimension_width_greater_than_or_equal_to: "ширина мусить бути більше або дорівнювати %{length} пікселям"
|
13
|
+
dimension_height_greater_than_or_equal_to: "висота мусить бути більше або дорівнювати %{length} пікселям"
|
14
|
+
dimension_width_less_than_or_equal_to: "ширина мусить бути менше або дорівнювати %{length} пікселям"
|
15
|
+
dimension_height_less_than_or_equal_to: "висота мусить бути менше або дорівнювати %{length} пікселям"
|
16
|
+
dimension_width_equal_to: "ширина мусить дорівнювати %{length} пікселям"
|
17
|
+
dimension_height_equal_to: "висота мусить дорівнювати %{length} пікселям"
|
18
|
+
aspect_ratio_not_square: "мусить бути квадратне зображення"
|
19
|
+
aspect_ratio_not_portrait: "мусить бути портретне зображення"
|
20
|
+
aspect_ratio_not_landscape: "мусить бути пейзажне зображення"
|
21
|
+
aspect_ratio_is_not: "мусить мати співвідношення сторін %{aspect_ratio}"
|
22
|
+
aspect_ratio_unknown: "має невідоме співвідношення сторін"
|
@@ -14,7 +14,7 @@ module ActiveStorageValidations
|
|
14
14
|
next if is_valid?(file)
|
15
15
|
|
16
16
|
errors_options[:content_type] = content_type(file)
|
17
|
-
record.errors.add(attribute, :content_type_invalid, errors_options)
|
17
|
+
record.errors.add(attribute, :content_type_invalid, **errors_options)
|
18
18
|
break
|
19
19
|
end
|
20
20
|
end
|
@@ -17,7 +17,7 @@ module ActiveStorageValidations
|
|
17
17
|
errors_options = { min: options[:min], max: options[:max] }
|
18
18
|
|
19
19
|
return true if files_count_valid?(files.count)
|
20
|
-
record.errors.add(attribute, options[:message].presence || :limit_out_of_range, errors_options)
|
20
|
+
record.errors.add(attribute, options[:message].presence || :limit_out_of_range, **errors_options)
|
21
21
|
end
|
22
22
|
|
23
23
|
def files_count_valid?(count)
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_storage_validations/matchers/attached_validator_matcher'
|
4
|
+
require 'active_storage_validations/matchers/content_type_validator_matcher'
|
5
|
+
require 'active_storage_validations/matchers/dimension_validator_matcher'
|
6
|
+
require 'active_storage_validations/matchers/size_validator_matcher'
|
7
|
+
|
8
|
+
module ActiveStorageValidations
|
9
|
+
module Matchers
|
10
|
+
# Helper to stub a method with either RSpec or Minitest (whatever is available)
|
11
|
+
def self.stub_method(object, method, result)
|
12
|
+
if defined?(Minitest::Mock)
|
13
|
+
object.stub(method, result) do
|
14
|
+
yield
|
15
|
+
end
|
16
|
+
elsif defined?(RSpec::Mocks)
|
17
|
+
RSpec::Mocks.allow_message(object, method) { result }
|
18
|
+
yield
|
19
|
+
else
|
20
|
+
raise 'Need either Minitest::Mock or RSpec::Mocks to run this validator matcher'
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.mock_metadata(attachment, width, height)
|
25
|
+
if Rails::VERSION::MAJOR >= 6
|
26
|
+
# Mock the Metadata class for rails 6
|
27
|
+
mock = OpenStruct.new(metadata: { width: width, height: height })
|
28
|
+
stub_method(ActiveStorageValidations::Metadata, :new, mock) do
|
29
|
+
yield
|
30
|
+
end
|
31
|
+
else
|
32
|
+
# Stub the metadata analysis for rails 5
|
33
|
+
stub_method(attachment, :analyze, true) do
|
34
|
+
stub_method(attachment, :analyzed?, true) do
|
35
|
+
stub_method(attachment, :metadata, { width: width, height: height }) do
|
36
|
+
yield
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveStorageValidations
|
4
|
+
module Matchers
|
5
|
+
def validate_attached_of(name)
|
6
|
+
AttachedValidatorMatcher.new(name)
|
7
|
+
end
|
8
|
+
|
9
|
+
class AttachedValidatorMatcher
|
10
|
+
def initialize(attribute_name)
|
11
|
+
@attribute_name = attribute_name
|
12
|
+
end
|
13
|
+
|
14
|
+
def description
|
15
|
+
"validate #{@attribute_name} must be attached"
|
16
|
+
end
|
17
|
+
|
18
|
+
def matches?(subject)
|
19
|
+
@subject = subject.is_a?(Class) ? subject.new : subject
|
20
|
+
responds_to_methods && valid_when_attached && invalid_when_not_attached
|
21
|
+
end
|
22
|
+
|
23
|
+
def failure_message
|
24
|
+
"is expected to validate attached of #{@attribute_name}"
|
25
|
+
end
|
26
|
+
|
27
|
+
def failure_message_when_negated
|
28
|
+
"is expected to not validate attached of #{@attribute_name}"
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def responds_to_methods
|
34
|
+
@subject.respond_to?(@attribute_name) &&
|
35
|
+
@subject.public_send(@attribute_name).respond_to?(:attach) &&
|
36
|
+
@subject.public_send(@attribute_name).respond_to?(:detach)
|
37
|
+
end
|
38
|
+
|
39
|
+
def valid_when_attached
|
40
|
+
@subject.public_send(@attribute_name).attach(attachable) unless @subject.public_send(@attribute_name).attached?
|
41
|
+
@subject.validate
|
42
|
+
@subject.errors.details[@attribute_name].exclude?(error: :blank)
|
43
|
+
end
|
44
|
+
|
45
|
+
def invalid_when_not_attached
|
46
|
+
@subject.public_send(@attribute_name).detach
|
47
|
+
# Unset the direct relation since `detach` on an unpersisted record does not set `attached?` to false.
|
48
|
+
@subject.public_send("#{@attribute_name}=", nil)
|
49
|
+
|
50
|
+
@subject.validate
|
51
|
+
@subject.errors.details[@attribute_name].include?(error: :blank)
|
52
|
+
end
|
53
|
+
|
54
|
+
def attachable
|
55
|
+
{ io: Tempfile.new('.'), filename: 'dummy.txt', content_type: 'text/plain' }
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Big thank you to the paperclip validation matchers:
|
4
|
+
# https://github.com/thoughtbot/paperclip/blob/v6.1.0/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb
|
5
|
+
module ActiveStorageValidations
|
6
|
+
module Matchers
|
7
|
+
def validate_content_type_of(name)
|
8
|
+
ContentTypeValidatorMatcher.new(name)
|
9
|
+
end
|
10
|
+
|
11
|
+
class ContentTypeValidatorMatcher
|
12
|
+
def initialize(attribute_name)
|
13
|
+
@attribute_name = attribute_name
|
14
|
+
end
|
15
|
+
|
16
|
+
def description
|
17
|
+
"validate the content types allowed on attachment #{@attribute_name}"
|
18
|
+
end
|
19
|
+
|
20
|
+
def allowing(*types)
|
21
|
+
@allowed_types = types.flatten
|
22
|
+
self
|
23
|
+
end
|
24
|
+
|
25
|
+
def rejecting(*types)
|
26
|
+
@rejected_types = types.flatten
|
27
|
+
self
|
28
|
+
end
|
29
|
+
|
30
|
+
def matches?(subject)
|
31
|
+
@subject = subject.is_a?(Class) ? subject.new : subject
|
32
|
+
responds_to_methods && allowed_types_allowed? && rejected_types_rejected?
|
33
|
+
end
|
34
|
+
|
35
|
+
def failure_message
|
36
|
+
<<~MESSAGE
|
37
|
+
Expected #{@attribute_name}
|
38
|
+
|
39
|
+
Accept content types: #{allowed_types.join(", ")}
|
40
|
+
#{accepted_types_and_failures}
|
41
|
+
|
42
|
+
Reject content types: #{rejected_types.join(", ")}
|
43
|
+
#{rejected_types_and_failures}
|
44
|
+
MESSAGE
|
45
|
+
end
|
46
|
+
|
47
|
+
protected
|
48
|
+
|
49
|
+
def responds_to_methods
|
50
|
+
@subject.respond_to?(@attribute_name) &&
|
51
|
+
@subject.public_send(@attribute_name).respond_to?(:attach) &&
|
52
|
+
@subject.public_send(@attribute_name).respond_to?(:detach)
|
53
|
+
end
|
54
|
+
|
55
|
+
def allowed_types
|
56
|
+
@allowed_types || []
|
57
|
+
end
|
58
|
+
|
59
|
+
def rejected_types
|
60
|
+
@rejected_types || (Mime::LOOKUP.keys - allowed_types)
|
61
|
+
end
|
62
|
+
|
63
|
+
def allowed_types_allowed?
|
64
|
+
@missing_allowed_types ||= allowed_types.reject { |type| type_allowed?(type) }
|
65
|
+
@missing_allowed_types.none?
|
66
|
+
end
|
67
|
+
|
68
|
+
def rejected_types_rejected?
|
69
|
+
@missing_rejected_types ||= rejected_types.select { |type| type_allowed?(type) }
|
70
|
+
@missing_rejected_types.none?
|
71
|
+
end
|
72
|
+
|
73
|
+
def accepted_types_and_failures
|
74
|
+
if @missing_allowed_types.present?
|
75
|
+
"#{@missing_allowed_types.join(", ")} were rejected."
|
76
|
+
else
|
77
|
+
"All were accepted successfully."
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def rejected_types_and_failures
|
82
|
+
if @missing_rejected_types.present?
|
83
|
+
"#{@missing_rejected_types.join(", ")} were accepted."
|
84
|
+
else
|
85
|
+
"All were rejected successfully."
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def type_allowed?(type)
|
90
|
+
@subject.public_send(@attribute_name).attach(attachment_for(type))
|
91
|
+
@subject.validate
|
92
|
+
@subject.errors.details[@attribute_name].all? { |error| error[:error] != :content_type_invalid }
|
93
|
+
end
|
94
|
+
|
95
|
+
def attachment_for(type)
|
96
|
+
suffix = type.to_s.split('/').last
|
97
|
+
{ io: Tempfile.new('.'), filename: "test.#{suffix}", content_type: type }
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveStorageValidations
|
4
|
+
module Matchers
|
5
|
+
def validate_dimensions_of(name)
|
6
|
+
DimensionValidatorMatcher.new(name)
|
7
|
+
end
|
8
|
+
|
9
|
+
class DimensionValidatorMatcher
|
10
|
+
def initialize(attribute_name)
|
11
|
+
@attribute_name = attribute_name
|
12
|
+
@width_min = @width_max = @height_min = @height_max = nil
|
13
|
+
end
|
14
|
+
|
15
|
+
def description
|
16
|
+
"validate image dimensions of #{@attribute_name}"
|
17
|
+
end
|
18
|
+
|
19
|
+
def width_min(width)
|
20
|
+
@width_min = width
|
21
|
+
self
|
22
|
+
end
|
23
|
+
|
24
|
+
def width_max(width)
|
25
|
+
@width_max = width
|
26
|
+
self
|
27
|
+
end
|
28
|
+
|
29
|
+
def width(width)
|
30
|
+
@width_min = @width_max = width
|
31
|
+
self
|
32
|
+
end
|
33
|
+
|
34
|
+
def height_min(height)
|
35
|
+
@height_min = height
|
36
|
+
self
|
37
|
+
end
|
38
|
+
|
39
|
+
def height_max(height)
|
40
|
+
@height_max = height
|
41
|
+
self
|
42
|
+
end
|
43
|
+
|
44
|
+
def width_between(range)
|
45
|
+
@width_min, @width_max = range.first, range.last
|
46
|
+
self
|
47
|
+
end
|
48
|
+
|
49
|
+
def height_between(range)
|
50
|
+
@height_min, @height_max = range.first, range.last
|
51
|
+
self
|
52
|
+
end
|
53
|
+
|
54
|
+
def height(height)
|
55
|
+
@height_min = @height_max = height
|
56
|
+
self
|
57
|
+
end
|
58
|
+
|
59
|
+
def matches?(subject)
|
60
|
+
@subject = subject.is_a?(Class) ? subject.new : subject
|
61
|
+
responds_to_methods &&
|
62
|
+
width_smaller_than_min? && width_larger_than_min? && width_smaller_than_max? && width_larger_than_max? && width_equals? &&
|
63
|
+
height_smaller_than_min? && height_larger_than_min? && height_smaller_than_max? && height_larger_than_max? && height_equals?
|
64
|
+
end
|
65
|
+
|
66
|
+
def failure_message
|
67
|
+
<<~MESSAGE
|
68
|
+
is expected to validate dimensions of #{@attribute_name}
|
69
|
+
width between #{@width_min} and #{@width_max}
|
70
|
+
height between #{@height_min} and #{@height_max}
|
71
|
+
MESSAGE
|
72
|
+
end
|
73
|
+
|
74
|
+
protected
|
75
|
+
|
76
|
+
def responds_to_methods
|
77
|
+
@subject.respond_to?(@attribute_name) &&
|
78
|
+
@subject.public_send(@attribute_name).respond_to?(:attach) &&
|
79
|
+
@subject.public_send(@attribute_name).respond_to?(:detach)
|
80
|
+
end
|
81
|
+
|
82
|
+
def valid_width
|
83
|
+
((@width_min || 0) + (@width_max || 2000)) / 2
|
84
|
+
end
|
85
|
+
|
86
|
+
def valid_height
|
87
|
+
((@height_min || 0) + (@height_max || 2000)) / 2
|
88
|
+
end
|
89
|
+
|
90
|
+
def width_smaller_than_min?
|
91
|
+
@width_min.nil? || !passes_validation_with_dimensions(@width_min - 1, valid_height, 'width')
|
92
|
+
end
|
93
|
+
|
94
|
+
def width_larger_than_min?
|
95
|
+
@width_min.nil? || @width_min == @width_max || passes_validation_with_dimensions(@width_min + 1, valid_height, 'width')
|
96
|
+
end
|
97
|
+
|
98
|
+
def width_smaller_than_max?
|
99
|
+
@width_max.nil? || @width_min == @width_max || passes_validation_with_dimensions(@width_max - 1, valid_height, 'width')
|
100
|
+
end
|
101
|
+
|
102
|
+
def width_larger_than_max?
|
103
|
+
@width_max.nil? || !passes_validation_with_dimensions(@width_max + 1, valid_height, 'width')
|
104
|
+
end
|
105
|
+
|
106
|
+
def width_equals?
|
107
|
+
@width_min.nil? || @width_min != @width_max || passes_validation_with_dimensions(@width_min, valid_height, 'width')
|
108
|
+
end
|
109
|
+
|
110
|
+
def height_smaller_than_min?
|
111
|
+
@height_min.nil? || !passes_validation_with_dimensions(valid_width, @height_min - 1, 'height')
|
112
|
+
end
|
113
|
+
|
114
|
+
def height_larger_than_min?
|
115
|
+
@height_min.nil? || @height_min == @height_max || passes_validation_with_dimensions(valid_width, @height_min + 1, 'height')
|
116
|
+
end
|
117
|
+
|
118
|
+
def height_smaller_than_max?
|
119
|
+
@height_max.nil? || @height_min == @height_max || passes_validation_with_dimensions(valid_width, @height_max - 1, 'height')
|
120
|
+
end
|
121
|
+
|
122
|
+
def height_larger_than_max?
|
123
|
+
@height_max.nil? || !passes_validation_with_dimensions(valid_width, @height_max + 1, 'height')
|
124
|
+
end
|
125
|
+
|
126
|
+
def height_equals?
|
127
|
+
@height_min.nil? || @height_min != @height_max || passes_validation_with_dimensions(valid_width, @height_min, 'height')
|
128
|
+
end
|
129
|
+
|
130
|
+
def passes_validation_with_dimensions(width, height, check)
|
131
|
+
@subject.public_send(@attribute_name).attach attachment_for(width, height)
|
132
|
+
|
133
|
+
attachment = @subject.public_send(@attribute_name)
|
134
|
+
Matchers.mock_metadata(attachment, width, height) do
|
135
|
+
@subject.validate
|
136
|
+
@subject.errors.details[@attribute_name].all? { |error| error[:error].to_s.exclude?("dimension_#{check}") }
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def attachment_for(width, height)
|
141
|
+
{ io: Tempfile.new('Hello world!'), filename: 'test.png', content_type: 'image/png' }
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Big thank you to the paperclip validation matchers:
|
4
|
+
# https://github.com/thoughtbot/paperclip/blob/v6.1.0/lib/paperclip/matchers/validate_attachment_size_matcher.rb
|
5
|
+
module ActiveStorageValidations
|
6
|
+
module Matchers
|
7
|
+
def validate_size_of(name)
|
8
|
+
SizeValidatorMatcher.new(name)
|
9
|
+
end
|
10
|
+
|
11
|
+
class SizeValidatorMatcher
|
12
|
+
def initialize(attribute_name)
|
13
|
+
@attribute_name = attribute_name
|
14
|
+
@low = @high = nil
|
15
|
+
end
|
16
|
+
|
17
|
+
def description
|
18
|
+
"validate file size of #{@attribute_name}"
|
19
|
+
end
|
20
|
+
|
21
|
+
def less_than(size)
|
22
|
+
@high = size - 1.byte
|
23
|
+
self
|
24
|
+
end
|
25
|
+
|
26
|
+
def less_than_or_equal_to(size)
|
27
|
+
@high = size
|
28
|
+
self
|
29
|
+
end
|
30
|
+
|
31
|
+
def greater_than(size)
|
32
|
+
@low = size + 1.byte
|
33
|
+
self
|
34
|
+
end
|
35
|
+
|
36
|
+
def greater_than_or_equal_to(size)
|
37
|
+
@low = size
|
38
|
+
self
|
39
|
+
end
|
40
|
+
|
41
|
+
def between(range)
|
42
|
+
@low, @high = range.first, range.last
|
43
|
+
self
|
44
|
+
end
|
45
|
+
|
46
|
+
def matches?(subject)
|
47
|
+
@subject = subject.is_a?(Class) ? subject.new : subject
|
48
|
+
responds_to_methods && lower_than_low? && higher_than_low? && lower_than_high? && higher_than_high?
|
49
|
+
end
|
50
|
+
|
51
|
+
def failure_message
|
52
|
+
"is expected to validate file size of #{@attribute_name} to be between #{@low} and #{@high} bytes"
|
53
|
+
end
|
54
|
+
|
55
|
+
def failure_message_when_negated
|
56
|
+
"is expected to not validate file size of #{@attribute_name} to be between #{@low} and #{@high} bytes"
|
57
|
+
end
|
58
|
+
|
59
|
+
protected
|
60
|
+
|
61
|
+
def responds_to_methods
|
62
|
+
@subject.respond_to?(@attribute_name) &&
|
63
|
+
@subject.public_send(@attribute_name).respond_to?(:attach) &&
|
64
|
+
@subject.public_send(@attribute_name).respond_to?(:detach)
|
65
|
+
end
|
66
|
+
|
67
|
+
def lower_than_low?
|
68
|
+
@low.nil? || !passes_validation_with_size(@low - 1)
|
69
|
+
end
|
70
|
+
|
71
|
+
def higher_than_low?
|
72
|
+
@low.nil? || passes_validation_with_size(@low + 1)
|
73
|
+
end
|
74
|
+
|
75
|
+
def lower_than_high?
|
76
|
+
@high.nil? || @high == Float::INFINITY || passes_validation_with_size(@high - 1)
|
77
|
+
end
|
78
|
+
|
79
|
+
def higher_than_high?
|
80
|
+
@high.nil? || @high == Float::INFINITY || !passes_validation_with_size(@high + 1)
|
81
|
+
end
|
82
|
+
|
83
|
+
def passes_validation_with_size(new_size)
|
84
|
+
io = Tempfile.new('Hello world!')
|
85
|
+
Matchers.stub_method(io, :size, new_size) do
|
86
|
+
@subject.public_send(@attribute_name).attach(io: io, filename: 'test.png', content_type: 'image/pg')
|
87
|
+
@subject.validate
|
88
|
+
@subject.errors.details[@attribute_name].all? { |error| error[:error] != :file_size_out_of_range }
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -19,11 +19,22 @@ module ActiveStorageValidations
|
|
19
19
|
private
|
20
20
|
|
21
21
|
def read_image
|
22
|
-
|
23
|
-
|
22
|
+
is_string = file.is_a?(String)
|
23
|
+
if is_string || file.is_a?(ActiveStorage::Blob)
|
24
|
+
if is_string
|
25
|
+
# If Rails 5.2 or 6.0, use `find_signed`
|
26
|
+
if Rails::VERSION::MAJOR < 6 || (Rails::VERSION::MAJOR == 6 && Rails::VERSION::MINOR == 0)
|
27
|
+
blob = ActiveStorage::Blob.find_signed(file)
|
28
|
+
# If Rails 6.1 or higher, use `find_signed!`
|
29
|
+
elsif Rails::VERSION::MAJOR > 6 || (Rails::VERSION::MAJOR == 6 && Rails::VERSION::MINOR >= 1)
|
30
|
+
blob = ActiveStorage::Blob.find_signed!(file)
|
31
|
+
end
|
32
|
+
else
|
33
|
+
blob = file
|
34
|
+
end
|
24
35
|
|
25
36
|
tempfile = Tempfile.new(["ActiveStorage-#{blob.id}-", blob.filename.extension_with_delimiter])
|
26
|
-
tempfile.binmode
|
37
|
+
tempfile.binmode
|
27
38
|
|
28
39
|
blob.download do |chunk|
|
29
40
|
tempfile.write(chunk)
|
@@ -25,7 +25,7 @@ module ActiveStorageValidations
|
|
25
25
|
next if content_size_valid?(file.blob.byte_size)
|
26
26
|
|
27
27
|
errors_options[:file_size] = number_to_human_size(file.blob.byte_size)
|
28
|
-
record.errors.add(attribute, :file_size_out_of_range, errors_options)
|
28
|
+
record.errors.add(attribute, :file_size_out_of_range, **errors_options)
|
29
29
|
break
|
30
30
|
end
|
31
31
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_storage_validations
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.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: 2020-
|
11
|
+
date: 2020-12-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -80,20 +80,6 @@ dependencies:
|
|
80
80
|
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
|
-
name: coffee-rails
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
86
|
-
requirements:
|
87
|
-
- - ">="
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
version: '0'
|
90
|
-
type: :development
|
91
|
-
prerelease: false
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
93
|
-
requirements:
|
94
|
-
- - ">="
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
version: '0'
|
97
83
|
description: Validations for Active Storage (presence)
|
98
84
|
email:
|
99
85
|
- igorkasyanchuk@gmail.com
|
@@ -106,9 +92,13 @@ files:
|
|
106
92
|
- Rakefile
|
107
93
|
- config/locales/de.yml
|
108
94
|
- config/locales/en.yml
|
95
|
+
- config/locales/es.yml
|
109
96
|
- config/locales/fr.yml
|
97
|
+
- config/locales/ja.yml
|
98
|
+
- config/locales/nl.yml
|
110
99
|
- config/locales/pt-BR.yml
|
111
100
|
- config/locales/ru.yml
|
101
|
+
- config/locales/tr.yml
|
112
102
|
- config/locales/uk.yml
|
113
103
|
- lib/active_storage_validations.rb
|
114
104
|
- lib/active_storage_validations/aspect_ratio_validator.rb
|
@@ -117,6 +107,11 @@ files:
|
|
117
107
|
- lib/active_storage_validations/dimension_validator.rb
|
118
108
|
- lib/active_storage_validations/engine.rb
|
119
109
|
- lib/active_storage_validations/limit_validator.rb
|
110
|
+
- lib/active_storage_validations/matchers.rb
|
111
|
+
- lib/active_storage_validations/matchers/attached_validator_matcher.rb
|
112
|
+
- lib/active_storage_validations/matchers/content_type_validator_matcher.rb
|
113
|
+
- lib/active_storage_validations/matchers/dimension_validator_matcher.rb
|
114
|
+
- lib/active_storage_validations/matchers/size_validator_matcher.rb
|
120
115
|
- lib/active_storage_validations/metadata.rb
|
121
116
|
- lib/active_storage_validations/railtie.rb
|
122
117
|
- lib/active_storage_validations/size_validator.rb
|
@@ -141,7 +136,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
141
136
|
- !ruby/object:Gem::Version
|
142
137
|
version: '0'
|
143
138
|
requirements: []
|
144
|
-
rubygems_version: 3.0.
|
139
|
+
rubygems_version: 3.0.3
|
145
140
|
signing_key:
|
146
141
|
specification_version: 4
|
147
142
|
summary: Validations for Active Storage
|