Skip to content

Commit b7bb967

Browse files
authored
Merge pull request #1 from Syati/error_format
Improve error handling and serialization features
2 parents 21c6189 + 2ddc265 commit b7bb967

16 files changed

Lines changed: 1225 additions & 429 deletions

README.md

Lines changed: 31 additions & 186 deletions
Original file line numberDiff line numberDiff line change
@@ -11,238 +11,83 @@ English | [日本語](README_ja.md)
1111
- **Array handling** for both primitive types and nested objects
1212
- **Strong Parameters integration** with automatic permit lists
1313
- **ActiveModel compatibility** with validations and serialization
14+
- **Enhanced error handling** with flat and structured formats
1415
- **RBS type definitions** for better development experience
1516

16-
## Installation
17-
18-
Add this line to your application's Gemfile:
17+
## Quick Start
1918

2019
```ruby
20+
# 1. Install the gem
2121
gem 'structured_params'
22-
```
23-
24-
And then execute:
25-
26-
```bash
27-
$ bundle install
28-
```
29-
30-
Or install it yourself as:
31-
32-
```bash
33-
$ gem install structured_params
34-
```
35-
36-
## Setup
3722

38-
Register the custom types in your Rails application:
39-
40-
```ruby
41-
# config/initializers/structured_params.rb
23+
# 2. Register types in initializer
4224
StructuredParams.register_types
43-
```
44-
45-
This registers `:object` and `:array` types with ActiveModel::Type.
46-
47-
## Usage
4825

49-
### Basic Parameter Class
50-
51-
```ruby
26+
# 3. Define parameter classes
5227
class UserParams < StructuredParams::Params
5328
attribute :name, :string
5429
attribute :age, :integer
55-
attribute :email, :string
30+
attribute :address, :object, value_class: AddressParams
31+
attribute :hobbies, :array, value_class: HobbyParams
5632

5733
validates :name, presence: true
58-
validates :email, format: { with: URI::MailTo::EMAIL_REGEXP }
34+
validates :age, numericality: { greater_than: 0 }
5935
end
6036

61-
# Usage in controller
37+
# 4. Use in controllers
6238
def create
6339
user_params = UserParams.new(params[:user])
6440
if user_params.valid?
6541
User.create!(user_params.attributes)
6642
else
67-
render json: { errors: user_params.errors }
43+
render json: { errors: user_params.errors.to_hash(false, structured: true) }
6844
end
6945
end
7046
```
7147

72-
### Nested Objects
48+
## Documentation
49+
50+
- **[Installation and Setup](docs/installation.md)** - Getting started with StructuredParams
51+
- **[Basic Usage](docs/basic-usage.md)** - Parameter classes, nested objects, and arrays
52+
- **[Validation](docs/validation.md)** - Using ActiveModel validations with nested structures
53+
- **[Strong Parameters](docs/strong-parameters.md)** - Automatic permit list generation
54+
- **[Error Handling](docs/error-handling.md)** - Flat and structured error formats
55+
- **[Serialization](docs/serialization.md)** - Converting parameters to hashes and JSON
56+
- **[Advanced Usage](docs/advanced-usage.md)** - Type introspection, performance tips, and more
57+
58+
## Example
7359

7460
```ruby
7561
class AddressParams < StructuredParams::Params
7662
attribute :street, :string
7763
attribute :city, :string
7864
attribute :postal_code, :string
65+
66+
validates :street, :city, :postal_code, presence: true
7967
end
8068

8169
class UserParams < StructuredParams::Params
8270
attribute :name, :string
71+
attribute :email, :string
8372
attribute :address, :object, value_class: AddressParams
73+
74+
validates :name, presence: true
75+
validates :email, format: { with: URI::MailTo::EMAIL_REGEXP }
8476
end
8577

8678
# Usage
8779
params = {
8880
name: "John Doe",
89-
address: {
90-
street: "123 Main St",
91-
city: "New York",
92-
postal_code: "10001"
93-
}
81+
email: "john@example.com",
82+
address: { street: "123 Main St", city: "New York", postal_code: "10001" }
9483
}
9584

9685
user_params = UserParams.new(params)
97-
user_params.address # => AddressParams instance
86+
user_params.valid? # => true
9887
user_params.address.city # => "New York"
88+
user_params.attributes # => Hash ready for ActiveRecord
9989
```
10090

101-
### Arrays
102-
103-
#### Array of Primitive Types
104-
105-
```ruby
106-
class UserParams < StructuredParams::Params
107-
attribute :tags, :array, value_type: :string
108-
attribute :scores, :array, value_type: :integer
109-
end
110-
111-
# Usage
112-
params = {
113-
tags: ["ruby", "rails", "programming"],
114-
scores: [85, 92, 78]
115-
}
116-
117-
user_params = UserParams.new(params)
118-
user_params.tags # => ["ruby", "rails", "programming"]
119-
user_params.scores # => [85, 92, 78]
120-
```
121-
122-
#### Array of Nested Objects
123-
124-
```ruby
125-
class HobbyParams < StructuredParams::Params
126-
attribute :name, :string
127-
attribute :level, :string
128-
end
129-
130-
class UserParams < StructuredParams::Params
131-
attribute :name, :string
132-
attribute :hobbies, :array, value_class: HobbyParams
133-
end
134-
135-
# Usage
136-
params = {
137-
name: "Alice",
138-
hobbies: [
139-
{ name: "Photography", level: "beginner" },
140-
{ name: "Cooking", level: "intermediate" }
141-
]
142-
}
143-
144-
user_params = UserParams.new(params)
145-
user_params.hobbies # => [HobbyParams, HobbyParams]
146-
user_params.hobbies.first.name # => "Photography"
147-
```
148-
149-
### Strong Parameters Integration
150-
151-
StructuredParams automatically generates permit lists for Strong Parameters:
152-
153-
```ruby
154-
class UsersController < ApplicationController
155-
def create
156-
permitted_params = params.require(:user).permit(*UserParams.permit_attribute_names)
157-
user_params = UserParams.new(permitted_params)
158-
159-
if user_params.valid?
160-
User.create!(user_params.attributes)
161-
else
162-
render json: { errors: user_params.errors }
163-
end
164-
end
165-
end
166-
167-
# UserParams.permit_attribute_names returns:
168-
# [:name, :age, :email, { address: [:street, :city, :postal_code] }, { hobbies: [:name, :level] }]
169-
```
170-
171-
### Validation
172-
173-
Since StructuredParams inherits from ActiveModel, you can use all ActiveModel validations:
174-
175-
```ruby
176-
class UserParams < StructuredParams::Params
177-
attribute :name, :string
178-
attribute :age, :integer
179-
attribute :email, :string
180-
attribute :address, :object, value_class: AddressParams
181-
182-
validates :name, presence: true, length: { minimum: 2 }
183-
validates :age, presence: true, numericality: { greater_than: 0 }
184-
validates :email, presence: true, format: { with: URI::MailTo::EMAIL_REGEXP }
185-
validates :address, presence: true
186-
187-
validate :custom_validation
188-
189-
private
190-
191-
def custom_validation
192-
errors.add(:age, "must be adult") if age && age < 18
193-
end
194-
end
195-
```
196-
197-
### Serialization
198-
199-
```ruby
200-
user_params = UserParams.new(params)
201-
user_params.attributes # => Hash with all attributes
202-
user_params.to_json # => JSON string
203-
```
204-
205-
## Advanced Usage
206-
207-
### Custom Type Registration
208-
209-
If you want to avoid potential naming conflicts, you can register types with custom names:
210-
211-
```ruby
212-
# Register with custom names
213-
StructuredParams.register_types_as(
214-
object_name: :structured_object,
215-
array_name: :structured_array
216-
)
217-
218-
# Then use in your parameter classes
219-
class UserParams < StructuredParams::Params
220-
attribute :address, :structured_object, value_class: AddressParams
221-
attribute :hobbies, :structured_array, value_class: HobbyParams
222-
end
223-
```
224-
225-
### Type Introspection
226-
227-
```ruby
228-
user_params = UserParams.new(params)
229-
230-
# Check attribute types
231-
UserParams.attribute_types[:name].type # => :string
232-
UserParams.attribute_types[:address].type # => :object
233-
UserParams.attribute_types[:hobbies].type # => :array
234-
235-
# Access nested value classes
236-
UserParams.attribute_types[:address].value_class # => AddressParams
237-
UserParams.attribute_types[:hobbies].value_class # => HobbyParams
238-
```
239-
240-
## Development
241-
242-
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
243-
244-
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
245-
24691
## Contributing
24792

24893
Bug reports and pull requests are welcome on GitHub at https://github.com/Syati/structured_params.

0 commit comments

Comments
 (0)