activestorage-validator 0.5.0 → 0.6.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: eb2851d4b64cc39176ceaba155c80ac8989930899110e55f471c67df9d78a1bc
4
- data.tar.gz: ea620cd996d2b50cf53e058fb43acc89652c5edaaa754de8f333855bab4f177e
3
+ metadata.gz: 6b66feb405437ad34641613c818d1fee5d8130235ab77b30ab07630ca7a09560
4
+ data.tar.gz: 00417b87e52603376cca1afc253e336b8ac5a090fbdbb386f43ae2062a73bdb0
5
5
  SHA512:
6
- metadata.gz: 9288e28946a1e1fb38691329eae86807c4d781116b2f64b389a6bc4e8b3c8e87c0cff3342c1bf716693126d84d64d553a0abddd2ae7a99e4fd28855f9940f0db
7
- data.tar.gz: 6098588122be931263ae237cd6e486c1a975e446578502179f6b2064ed54ef1397431e3a23ce9aa1c086ecddc3fc49e42a2d402ed725472b57587ca8cc42d975
6
+ metadata.gz: 457cd27983de69c7d3e1e0f9c9226fb5b67410be17e4f64132220ce0953a4c4a9345eed292628343eb4f373bbdd83aab501f6036eb689a2627f86cff22207c49
7
+ data.tar.gz: a7ea46c6d09ea311b7329bc63b94355c543a568a562d8db413f447a479238aae295d42edbcf29665969b4083af97624ad16a8d984a9e41120fee2dac68135f92
@@ -44,7 +44,7 @@ jobs:
44
44
  sudo apt update -y
45
45
  sudo apt install -y libsqlite3-dev
46
46
 
47
- - uses: actions/checkout@v4
47
+ - uses: actions/checkout@v6
48
48
 
49
49
  - name: Set up Ruby
50
50
  uses: ruby/setup-ruby@v1
data/README.md CHANGED
@@ -3,43 +3,126 @@
3
3
 
4
4
  # ActiveStorage Validator
5
5
 
6
- ActiveStorage blob validator.
6
+ A Rails gem that makes it easy to add validations such as `content_type` and file size to ActiveStorage attachments.
7
+
8
+ - Supports both `has_one_attached` and `has_many_attached` of ActiveStorage
9
+ - Flexible validations for content type and file size
7
10
 
8
11
  ## Installation
9
12
 
13
+ ### Using Bundler
14
+
10
15
  Add this line to your application's Gemfile:
11
16
 
12
17
  ```ruby
13
18
  gem 'activestorage-validator'
14
19
  ```
15
20
 
16
- And then execute:
21
+ Then execute:
17
22
 
18
- $ bundle
23
+ $ bundle install
19
24
 
20
- Or install it yourself as:
25
+ ### Install with gem command
21
26
 
22
27
  $ gem install activestorage-validator
23
28
 
24
29
  ## Usage
25
30
 
31
+ You can add validations to models with ActiveStorage attachments using the `blob` validator.
32
+
26
33
  ```ruby
27
34
  class User < ApplicationRecord
28
35
  has_one_attached :avatar
29
36
  has_many_attached :photos
30
37
 
31
- validates :avatar, presence: true, blob: { content_type: :web_image } # supported options: :web_image, :image, :audio, :video, :text
32
- validates :photos, presence: true, blob: { content_type: ['image/png', 'image/jpg', 'image/jpeg'], size_range: 1..(5.megabytes) }
33
- # validates :photos, presence: true, blob: { content_type: %r{^image/}, size_range: 1..(5.megabytes) }
38
+ # Allow only web image files
39
+ validates :avatar, presence: true, blob: { content_type: :web_image }
40
+
41
+ # Allow only JPEG/PNG, up to 5MB per file
42
+ validates :photos, presence: true, blob: { content_type: ["image/png", "image/jpg", "image/jpeg"], size_range: 1..(5.megabytes) }
43
+
44
+ # You can also use a regular expression for content_type
45
+ # validates :photos, blob: { content_type: %r{^image/}, size_range: 1..(5.megabytes) }
46
+
47
+ # Require the filename to have one of the allowed extensions
48
+ # validates :audio, blob: { content_type: "audio/mpeg", extension: %w[mp3] }
34
49
  end
35
50
  ```
36
51
 
37
- Note: For `has_many_attached`, size is validated on each file individually. In the code above, `:photos` validation allows any number of photos to be upload, each one being 5 MB or less in size.
52
+ > **Note:** For `has_many_attached`, the size validation is applied to each file individually.
53
+
54
+ ## Validation Options
55
+
56
+ | Option | Description |
57
+ |--------------|---------------------------------------------------------------------------------------------|
58
+ | content_type | Allowed MIME types. Accepts a symbol (`:web_image`, `:image`, `:audio`, `:video`, `:text`), an array of MIME types, a regular expression, or a string (single MIME type). |
59
+ | size_range | Allowed file size range (e.g. `1..5.megabytes`) |
60
+ | extension | Allowed file extensions. Accepts a String or an Array of Strings. Case-insensitive, leading dot optional. Files without an extension are rejected. |
61
+
62
+ ### content_type Examples
63
+
64
+ - **Symbol**
65
+ - `:web_image` ... PNG, JPEG, GIF, WebP (special handling)
66
+ - `:image`, `:audio`, `:video`, `:text` ... Calls `blob.image?`, `blob.audio?`, etc. (ActiveStorage built-in predicate)
67
+ - **Array**
68
+ - `["image/png", "image/jpg", "image/jpeg"]` ... Only allow these MIME types
69
+ - **Regexp**
70
+ - `%r{^image/}` ... Allow any image type (MIME type starts with `image/`)
71
+ - **String**
72
+ - `"application/pdf"` ... Only allow PDF files
73
+
74
+ ### extension Examples
75
+
76
+ - **String**
77
+ - `extension: "mp3"` ... Only allow `.mp3` files
78
+ - **Array**
79
+ - `extension: %w[mp3 m4a]` ... Allow either `.mp3` or `.m4a`
80
+ - **Combined with content_type (AND)**
81
+ - `blob: { content_type: "audio/mpeg", extension: %w[mp3] }` ... Reject both `my_podcast` (no extension) and `my_podcast.wav` (wrong extension), even when their MIME types match.
82
+
83
+ The leading dot is optional (`"mp3"` and `".mp3"` behave the same), and matching is case-insensitive (`PHOTO.JPG` matches `extension: "jpg"`).
84
+
85
+ ## I18n Error Message Options
86
+
87
+ Validation error messages are I18n compatible. The following interpolation keys are available in your translation files, according to the validator's implementation:
88
+
89
+ | Key | Description |
90
+ |----------------|---------------------------------------------|
91
+ | filename | The uploaded file's name |
92
+ | min_size | The minimum allowed file size (humanized) |
93
+ | max_size | The maximum allowed file size (humanized) |
94
+ | extension | The list of allowed extensions, joined by `, ` |
95
+
96
+ The following error types are used:
97
+
98
+ - `content_type` (invalid content type)
99
+ - `min_size_error` (file is too small)
100
+ - `max_size_error` (file is too large)
101
+ - `extension` (invalid file extension)
102
+
103
+ Example (config/locales/en.yml):
104
+
105
+ ```yaml
106
+ en:
107
+ errors:
108
+ messages:
109
+ content_type: "%{filename} has an invalid content type"
110
+ min_size_error: "%{filename} is too small (minimum is %{min_size})"
111
+ max_size_error: "%{filename} is too large (maximum is %{max_size})"
112
+ extension: "%{filename} has an invalid file extension (allowed: %{extension})"
113
+ ```
114
+
115
+ ## Notes
116
+
117
+ - Some features may not work depending on your ActiveStorage or Rails version.
118
+ - Validation error messages are I18n compatible and support interpolation keys as described above.
38
119
 
39
120
  ## Contributing
40
121
 
41
- Bug reports and pull requests are welcome on GitHub at https://github.com/aki77/activestorage-validator. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
122
+ Bug reports and pull requests are welcome on GitHub via [issues](https://github.com/aki77/activestorage-validator/issues) or [pull requests](https://github.com/aki77/activestorage-validator/pulls).
123
+
124
+ This project adheres to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
42
125
 
43
126
  ## License
44
127
 
45
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
128
+ This gem is released under the MIT License. See [LICENSE.txt](LICENSE.txt) for details.
@@ -5,3 +5,4 @@ de:
5
5
  content_type: "ist kein gültiges Dateiformat"
6
6
  min_size_error: "Dateigröße sollte weniger als %{min_size} betragen"
7
7
  max_size_error: "Dateigröße sollte weniger als %{max_size} betragen"
8
+ extension: "hat eine ungültige Dateierweiterung (erlaubt: %{extension})"
@@ -5,3 +5,4 @@ en:
5
5
  content_type: "is not a valid file format"
6
6
  min_size_error: "File size should be greater than %{min_size}"
7
7
  max_size_error: "File size should be less than %{max_size}"
8
+ extension: "has an invalid file extension (allowed: %{extension})"
@@ -5,3 +5,4 @@ es:
5
5
  content_type: "no es un formato válido"
6
6
  min_size_error: "tamaño de archivo debe ser mayor a %{min_size}"
7
7
  max_size_error: "tamaño de archivo debe ser menor a %{max_size}"
8
+ extension: "tiene una extensión de archivo no válida (permitidas: %{extension})"
@@ -5,3 +5,4 @@ fr:
5
5
  content_type: "n'est pas un format de fichier valide"
6
6
  min_size_error: "La taille du fichier doit être supérieure à %{min_size}"
7
7
  max_size_error: "La taille du fichier doit être inférieure à %{max_size}"
8
+ extension: "a une extension de fichier non valide (autorisées : %{extension})"
@@ -5,3 +5,4 @@ ja:
5
5
  content_type: "のファイル形式が不正です。"
6
6
  min_size_error: "を%{min_size}以上のサイズにしてください。"
7
7
  max_size_error: "を%{max_size}以下のサイズにしてください。"
8
+ extension: "のファイル拡張子が不正です(許可: %{extension})。"
@@ -5,3 +5,4 @@ pl:
5
5
  content_type: "ma nieprawidłowy format"
6
6
  min_size_error: "Rozmiar pliku nie może być większy niż %{min_size}"
7
7
  max_size_error: "Rozmiar pliku nie może być mniejszy niż %{max_size}"
8
+ extension: "ma nieprawidłowe rozszerzenie pliku (dozwolone: %{extension})"
@@ -5,3 +5,4 @@ pt-br:
5
5
  content_type: "não é um formato válido"
6
6
  min_size_error: "tamanho do arquivo deve ser maior que %{min_size}"
7
7
  max_size_error: "tamanho do arquivo deve ser menor que %{max_size}"
8
+ extension: "tem uma extensão de arquivo inválida (permitidas: %{extension})"
@@ -16,6 +16,15 @@ module ActiveRecord
16
16
  unless valid_content_type?(value.blob)
17
17
  record.errors.add(attribute, :content_type, filename: value.blob.filename.to_s)
18
18
  end
19
+
20
+ unless valid_extension?(value.blob)
21
+ record.errors.add(
22
+ attribute,
23
+ :extension,
24
+ filename: value.blob.filename.to_s,
25
+ extension: Array(options[:extension]).map { |e| normalize_extension(e) }.join(', ')
26
+ )
27
+ end
19
28
  end
20
29
  end
21
30
 
@@ -37,6 +46,20 @@ module ActiveRecord
37
46
  options[:content_type] == blob.content_type
38
47
  end
39
48
  end
49
+
50
+ def valid_extension?(blob)
51
+ return true if options[:extension].nil?
52
+
53
+ allowed = Array(options[:extension]).map { |e| normalize_extension(e) }
54
+ actual = normalize_extension(blob.filename.extension)
55
+ return false if actual.empty?
56
+
57
+ allowed.include?(actual)
58
+ end
59
+
60
+ def normalize_extension(value)
61
+ value.to_s.downcase.delete_prefix('.')
62
+ end
40
63
  end
41
64
  end
42
65
  end
@@ -1,5 +1,5 @@
1
1
  module ActiveStorage
2
2
  module Validator
3
- VERSION = '0.5.0'
3
+ VERSION = '0.6.0'
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activestorage-validator
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - aki
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-06-15 00:00:00.000000000 Z
10
+ date: 2026-04-29 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: rails