activestorage-validator 0.6.0 → 0.7.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: 6b66feb405437ad34641613c818d1fee5d8130235ab77b30ab07630ca7a09560
4
- data.tar.gz: 00417b87e52603376cca1afc253e336b8ac5a090fbdbb386f43ae2062a73bdb0
3
+ metadata.gz: acc9fae7338e419736df276e25e94e198cdc8a0ca9a2b80210c3175d684f5f22
4
+ data.tar.gz: 6b9be22b0d25c70bcf08cc51a05f9443982963d7e42e3817b90c60a596e5e071
5
5
  SHA512:
6
- metadata.gz: 457cd27983de69c7d3e1e0f9c9226fb5b67410be17e4f64132220ce0953a4c4a9345eed292628343eb4f373bbdd83aab501f6036eb689a2627f86cff22207c49
7
- data.tar.gz: a7ea46c6d09ea311b7329bc63b94355c543a568a562d8db413f447a479238aae295d42edbcf29665969b4083af97624ad16a8d984a9e41120fee2dac68135f92
6
+ metadata.gz: 57e1e9cd4353cfcb2aaeee8a2eef4bbedfe49b3382a3cacc7281fa1e5ec5ca1aa10158465a42e6eff8c2dbfd375b16f9ddb26c3027d1b337ca8fd0b41824c94b
7
+ data.tar.gz: 597d5cd7f32091fcf00a196fa4bd9d7404e5f129db45d0235c70768a01167d47ae9ec361b635b2732add9ba8be45c2bb2fef6db5a4b67e676130dfe7cf9fd13a
data/README.md CHANGED
@@ -117,6 +117,23 @@ en:
117
117
  - Some features may not work depending on your ActiveStorage or Rails version.
118
118
  - Validation error messages are I18n compatible and support interpolation keys as described above.
119
119
 
120
+ ## Agent skill
121
+
122
+ This repo ships an [agent skill](skills/activestorage-validator/) (`SKILL.md`,
123
+ plus a Japanese `SKILL-ja.md`) that teaches coding agents when and how to apply
124
+ `activestorage-validator`. Install it into your project with the GitHub CLI:
125
+
126
+ ```sh
127
+ gh skill install aki77/activestorage-validator
128
+ ```
129
+
130
+ > `gh skill` is currently a GitHub CLI preview feature.
131
+
132
+ Alternatively, if your project already pulls `activestorage-validator` in via
133
+ Bundler, the [bundler-skills](https://github.com/aki77/bundler-skills) plugin
134
+ auto-syncs this skill on `bundle install` — keeping the skill version locked to
135
+ the gem version.
136
+
120
137
  ## Contributing
121
138
 
122
139
  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).
@@ -17,7 +17,7 @@ Gem::Specification.new do |spec|
17
17
  # Specify which files should be added to the gem when it is released.
18
18
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
19
19
  spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
20
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
20
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) || f.match(%r{^skills/.*-ja\.md$}) }
21
21
  end
22
22
  spec.bindir = "exe"
23
23
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
@@ -1,5 +1,5 @@
1
1
  module ActiveStorage
2
2
  module Validator
3
- VERSION = '0.6.0'
3
+ VERSION = '0.7.0'
4
4
  end
5
5
  end
@@ -0,0 +1,132 @@
1
+ ---
2
+ name: activestorage-validator
3
+ description: "Validate ActiveStorage attachments (content type, file size, file extension) with the activestorage-validator gem's `blob` validator. Use when adding validations to has_one_attached / has_many_attached attributes."
4
+ ---
5
+
6
+ # activestorage-validator
7
+
8
+ A Rails gem that adds a `blob` validator for ActiveStorage attachments. It
9
+ validates content type, file size, and file extension on both
10
+ `has_one_attached` and `has_many_attached` attributes.
11
+
12
+ ## First: determine applicability
13
+
14
+ Use this gem **only** for validating ActiveStorage attachments. For ordinary
15
+ (non-attachment) attributes, use the standard Rails validators (`presence`,
16
+ `length`, `numericality`, etc.).
17
+
18
+ | What you validate | Tool |
19
+ | --- | --- |
20
+ | ActiveStorage attachment (content type / size / extension) | **`blob:` validator (this gem)** |
21
+ | Plain string/number/boolean columns | Standard Rails validators |
22
+ | Presence of the attachment itself | `presence: true` (works alongside `blob:`) |
23
+
24
+ There is no special read path — declare `validates ..., blob: { ... }` and the
25
+ attachment is validated like any other Rails validation on `save`/`valid?`.
26
+
27
+ ## Usage
28
+
29
+ Declare validations on the model with the `blob:` validator.
30
+
31
+ ```ruby
32
+ class User < ApplicationRecord
33
+ has_one_attached :avatar
34
+ has_many_attached :photos
35
+
36
+ # Allow only web image files (PNG, JPEG, GIF, WebP)
37
+ validates :avatar, presence: true, blob: { content_type: :web_image }
38
+
39
+ # Allow only JPEG/PNG, up to 5MB per file
40
+ validates :photos, presence: true, blob: {
41
+ content_type: ["image/png", "image/jpg", "image/jpeg"],
42
+ size_range: 1..(5.megabytes)
43
+ }
44
+
45
+ # Regexp content_type + required extension (AND condition)
46
+ validates :audio, blob: { content_type: "audio/mpeg", extension: %w[mp3] }
47
+ end
48
+ ```
49
+
50
+ > For `has_many_attached`, every option (including `size_range`) is applied to
51
+ > **each file individually**.
52
+
53
+ ## Options (all optional, combine freely)
54
+
55
+ | Option | Accepts | Notes |
56
+ | --- | --- | --- |
57
+ | `content_type` | Symbol / Array / Regexp / String | Allowed MIME type(s). See matching below. |
58
+ | `size_range` | Range | Allowed byte size, e.g. `1..(5.megabytes)`. |
59
+ | `extension` | String / Array | Allowed filename extension(s). |
60
+
61
+ ### `content_type` matching
62
+
63
+ - **`:web_image`** — special-cased to `ActiveStorage.web_image_content_types`
64
+ (PNG, JPEG, GIF, WebP). Use this instead of `:image` when you want only
65
+ browser-safe images.
66
+ - **Other Symbol** (`:image`, `:audio`, `:video`, `:text`) — calls the
67
+ ActiveStorage built-in predicate `blob.image?` / `blob.audio?` / etc.
68
+ - **Array** — `["image/png", "image/jpeg"]`: exact membership of the blob's
69
+ content type in the list.
70
+ - **Regexp** — `%r{^image/}`: matched against the blob's content type.
71
+ - **String** — `"application/pdf"`: exact equality.
72
+
73
+ ### `extension` matching
74
+
75
+ - Accepts a String (`"mp3"`) or Array (`%w[mp3 m4a]`).
76
+ - Leading dot is optional (`"mp3"` == `".mp3"`).
77
+ - Case-insensitive (`PHOTO.JPG` matches `extension: "jpg"`).
78
+ - **A file with no extension is always rejected** when `extension` is set.
79
+ - When combined with `content_type`, both must pass (AND). E.g.
80
+ `{ content_type: "audio/mpeg", extension: %w[mp3] }` rejects a `.wav` file
81
+ even if its MIME type happens to be `audio/mpeg`.
82
+
83
+ ## I18n error messages
84
+
85
+ Errors are I18n-compatible. Error types and their interpolation keys:
86
+
87
+ | Error type | Interpolation keys | When |
88
+ | --- | --- | --- |
89
+ | `content_type` | `filename` | content type not allowed |
90
+ | `min_size_error` | `filename`, `min_size` | smaller than `size_range.min` |
91
+ | `max_size_error` | `filename`, `max_size` | larger than `size_range.max` |
92
+ | `extension` | `filename`, `extension` | extension not allowed (or missing) |
93
+
94
+ `min_size` / `max_size` are humanized (`ActiveSupport::NumberHelper.number_to_human_size`).
95
+ `extension` is the allowed list joined by `, `.
96
+
97
+ ```yaml
98
+ # config/locales/en.yml
99
+ en:
100
+ errors:
101
+ messages:
102
+ content_type: "%{filename} has an invalid content type"
103
+ min_size_error: "%{filename} is too small (minimum is %{min_size})"
104
+ max_size_error: "%{filename} is too large (maximum is %{max_size})"
105
+ extension: "%{filename} has an invalid file extension (allowed: %{extension})"
106
+ ```
107
+
108
+ The gem ships default messages for 7 locales: `en`, `ja`, `de`, `es`, `fr`,
109
+ `pl`, `pt-br`. Override them in your app's locale files using the keys above.
110
+
111
+ ## Behavior details
112
+
113
+ - **Unattached values are skipped.** Validation returns early unless the
114
+ attachment is attached, so `blob:` does not enforce presence — add
115
+ `presence: true` separately if the attachment is required.
116
+ - **Size boundaries are inclusive.** A blob is valid when
117
+ `size_range.min <= byte_size <= size_range.max`. Below min → `min_size_error`;
118
+ above max → `max_size_error`.
119
+ - **Extension normalization** is `downcase` + strip a single leading dot; an
120
+ empty resulting extension (no extension on the file) fails.
121
+ - Options are independent — omit any you don't need; only the present ones run.
122
+
123
+ ## Pitfalls
124
+
125
+ - A file **without an extension** is rejected whenever `extension:` is set —
126
+ even if its content type is allowed. Don't set `extension:` if you accept
127
+ extension-less uploads.
128
+ - For `has_many_attached`, `size_range` applies **per file**, not to the total.
129
+ - `blob:` alone does **not** require an attachment; pair it with `presence: true`
130
+ when the upload is mandatory.
131
+ - No special read/preload path exists — this is a plain `EachValidator`; it runs
132
+ on standard `valid?` / `save`.
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.6.0
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - aki
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2026-04-29 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: rails
@@ -115,6 +115,7 @@ files:
115
115
  - lib/activestorage/validator.rb
116
116
  - lib/activestorage/validator/blob.rb
117
117
  - lib/activestorage/validator/version.rb
118
+ - skills/activestorage-validator/SKILL.md
118
119
  homepage: https://github.com/aki77/activestorage-validator
119
120
  licenses:
120
121
  - MIT
@@ -133,7 +134,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
133
134
  - !ruby/object:Gem::Version
134
135
  version: '0'
135
136
  requirements: []
136
- rubygems_version: 3.6.2
137
+ rubygems_version: 4.0.10
137
138
  specification_version: 4
138
139
  summary: ActiveStorage blob validator.
139
140
  test_files: []