Skip to content

Commit fe38d30

Browse files
committed
Add raw input validation support for score attribute in UserParams
1 parent 6961b3b commit fe38d30

4 files changed

Lines changed: 63 additions & 0 deletions

File tree

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,15 @@ end
4141
class UserParams < StructuredParams::Params
4242
attribute :name, :string
4343
attribute :age, :integer
44+
attribute :score, :integer
4445
attribute :tags, :array, value_type: :string # Primitive array
4546
attribute :address, :object, value_class: AddressParams # Nested object
4647

48+
# validate raw string before type casting
49+
validates_raw :score, format: { with: /\A\d+\z/, message: 'must be numeric string' }
4750
validates :name, presence: true
4851
validates :age, numericality: { greater_than: 0 }
52+
validates :score, numericality: { greater_than_or_equal_to: 0 }
4953
end
5054

5155
# Use in API controller

README_ja.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,15 @@ end
4141
class UserParams < StructuredParams::Params
4242
attribute :name, :string
4343
attribute :age, :integer
44+
attribute :score, :integer
4445
attribute :tags, :array, value_type: :string # プリミティブ配列
4546
attribute :address, :object, value_class: AddressParams # ネストオブジェクト
4647

48+
# 型変換前の生文字列をバリデーション
49+
validates_raw :score, format: { with: /\A\d+\z/, message: 'must be numeric string' }
4750
validates :name, presence: true
4851
validates :age, numericality: { greater_than: 0 }
52+
validates :score, numericality: { greater_than_or_equal_to: 0 }
4953
end
5054

5155
# API コントローラーで使用
@@ -61,6 +65,18 @@ def create
6165
end
6266
```
6367

68+
#### 型変換前の生入力をバリデーションする
69+
70+
ActiveModel の型変換前の入力値を検証したい場合は `validates_raw` を使います。
71+
72+
```ruby
73+
class UserParams < StructuredParams::Params
74+
attribute :age, :integer
75+
76+
validates_raw :age, format: { with: /\A\d+\z/, message: 'must be numeric string' }
77+
end
78+
```
79+
6480
### 2. フォームオブジェクト
6581

6682
```ruby

docs/validation.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,45 @@ class UserParams < StructuredParams::Params
2424
end
2525
```
2626

27+
## Validate Raw Input (`validates_raw`)
28+
29+
Use `validates_raw` to validate the original input value before type casting.
30+
31+
```ruby
32+
class UserParams < StructuredParams::Params
33+
attribute :age, :integer
34+
35+
validates_raw :age, format: { with: /\A\d+\z/, message: 'must be numeric string' }
36+
end
37+
38+
params = UserParams.new(age: '12x')
39+
params.valid? # => false
40+
params.errors.to_hash # => { age: ["must be numeric string"] }
41+
```
42+
43+
`validates_raw` uses `*_before_type_cast` internally, then remaps errors back to the original attribute.
44+
So `errors[:age_before_type_cast]` remains empty in normal usage.
45+
46+
### Combining `validates_raw` and `validates` on the same attribute
47+
48+
You can use both on the same attribute.
49+
50+
```ruby
51+
class UserParams < StructuredParams::Params
52+
attribute :score, :integer
53+
54+
validates_raw :score, format: { with: /\A\d+\z/, message: 'must be numeric string' }
55+
validates :score, numericality: { greater_than_or_equal_to: 0 }
56+
end
57+
58+
params = UserParams.new(score: 'abc')
59+
params.valid? # => false
60+
params.errors[:score]
61+
# => includes both "must be numeric string" and "is not a number"
62+
```
63+
64+
When both validations fail, both messages are added to the same attribute (`:score`).
65+
2766
## Nested Validation
2867

2968
Validation automatically cascades to nested objects and arrays:

lib/structured_params/params.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,13 @@ module StructuredParams
1111
# Strong Parameters example (API):
1212
# class UserParams < StructuredParams::Params
1313
# attribute :name, :string
14+
# attribute :age, :integer
1415
# attribute :address, :object, value_class: AddressParams
1516
# attribute :hobbies, :array, value_class: HobbyParams
1617
# attribute :tags, :array, value_type: :string
18+
#
19+
# # Validate raw input before type casting (e.g., "12x" for integer fields)
20+
# validates_raw :age, format: { with: /\A\d+\z/, message: 'must be numeric string' }
1721
# end
1822
#
1923
# # In controller:

0 commit comments

Comments
 (0)