From bb7bc640638f63b272df0483336342a38217274d Mon Sep 17 00:00:00 2001 From: mizuki-y Date: Sat, 6 Sep 2025 11:40:51 +0900 Subject: [PATCH] Add comparison document for StructuredParams and similar gems --- README.md | 1 + README_ja.md | 9 +- docs/comparison.md | 220 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 226 insertions(+), 4 deletions(-) create mode 100644 docs/comparison.md diff --git a/README.md b/README.md index 913054c..7999ee5 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,7 @@ end - **[Strong Parameters](docs/strong-parameters.md)** - Automatic permit list generation - **[Error Handling](docs/error-handling.md)** - Flat and structured error formats - **[Serialization](docs/serialization.md)** - Converting parameters to hashes and JSON +- **[Gem Comparison](docs/comparison.md)** - Comparison with typed_params, dry-validation, and reform ## Example diff --git a/README_ja.md b/README_ja.md index cbb1bce..d104e24 100644 --- a/README_ja.md +++ b/README_ja.md @@ -20,7 +20,7 @@ StructuredParams は、Rails アプリケーションでタイプセーフなパ # 1. gem をインストール gem 'structured_params' -# 2. イニ��ャライザで型を登録 +# 2. イニシャライザで型を登録 StructuredParams.register_types # 3. パラメータクラスを定義 @@ -49,10 +49,11 @@ end - **[インストールとセットアップ](docs/installation.md)** - StructuredParams の始め方 - **[基本的な使用方法](docs/basic-usage.md)** - パラメータクラス、ネストオブジェクト、配列 -- **[バリデーション](docs/validation.md)** - ネスト構造での ActiveModel バリデーション -- **[Strong Parameters](docs/strong-parameters.md)** - 自動 permit リスト生成 +- **[バリデーション](docs/validation.md)** - ネスト構造でのActiveModelバリデーション使用 +- **[Strong Parameters](docs/strong-parameters.md)** - 自動permit リスト生成 - **[エラーハンドリング](docs/error-handling.md)** - フラットと構造化エラーフォーマット -- **[シリアライゼーション](docs/serialization.md)** - パラメータのハッシュ・JSON変換 +- **[シリアライゼーション](docs/serialization.md)** - パラメータのハッシュとJSON変換 +- **[Gem比較](docs/comparison.md)** - typed_params、dry-validation、reformとの比較 ## 例 diff --git a/docs/comparison.md b/docs/comparison.md new file mode 100644 index 0000000..53766e0 --- /dev/null +++ b/docs/comparison.md @@ -0,0 +1,220 @@ +# Comparison with Similar Gems + +This document compares StructuredParams with other parameter handling gems in the Ruby/Rails ecosystem. + +## Overview Comparison + +| Feature | StructuredParams | typed_params | dry-validation | reform | +|---------|------------------|--------------|----------------|---------| +| Type Safety | ✅ ActiveModel::Type | ✅ Built-in types | ✅ Schema validation | ✅ Form objects | +| Nested Objects | ✅ Native support | ❌ Limited | ✅ Schema nesting | ✅ Composition | +| Array Handling | ✅ Typed arrays | ❌ Basic arrays | ✅ Array validation | ✅ Collection forms | +| Strong Parameters | ✅ Auto-generation | ❌ Manual | ❌ Manual | ❌ Manual | +| ActiveModel Integration | ✅ Full compatibility | ❌ Limited | ❌ None | ✅ Full compatibility | +| Error Handling | ✅ Flat & structured | ✅ Basic | ✅ Detailed | ✅ ActiveModel errors | +| RBS Support | ✅ Built-in | ❌ None | ❌ None | ❌ None | + +## Detailed Comparison + +### vs. typed_params + +**typed_params** provides basic type casting but lacks advanced features: + +```ruby +# typed_params - Basic usage +class UserController < ApplicationController + typed_params do + param :name, type: String, required: true + param :age, type: Integer + end +end + +# StructuredParams - Advanced features +class UserParams < StructuredParams::Params + attribute :name, :string + attribute :age, :integer + attribute :address, :object, value_class: AddressParams + attribute :hobbies, :array, value_class: HobbyParams + + validates :name, presence: true + validates :age, numericality: { greater_than: 0 } +end +``` + +**Advantages of StructuredParams:** +- Native nested object support +- Typed array handling +- Automatic Strong Parameters integration +- Full ActiveModel validation support +- Enhanced error handling with structured formats + +### vs. dry-validation + +**dry-validation** is a powerful validation library but requires more setup: + +```ruby +# dry-validation - Schema definition +UserContract = Dry::Validation.Contract do + params do + required(:name).filled(:string) + required(:age).filled(:integer) + optional(:address).hash do + required(:street).filled(:string) + required(:city).filled(:string) + end + end + + rule(:age) { failure('must be positive') if value <= 0 } +end + +# StructuredParams - Simpler approach +class UserParams < StructuredParams::Params + attribute :name, :string + attribute :age, :integer + attribute :address, :object, value_class: AddressParams + + validates :name, presence: true + validates :age, numericality: { greater_than: 0 } +end +``` + +**Advantages of StructuredParams:** +- More Rails-friendly syntax +- Built-in Strong Parameters support +- ActiveModel compatibility for serialization +- Less boilerplate code +- Native object composition + +### vs. reform + +**reform** provides form objects but with different focus: + +```ruby +# reform - Form object approach +class UserForm < Reform::Form + property :name + property :age + + collection :addresses do + property :street + property :city + end + + validates :name, presence: true +end + +# StructuredParams - Parameter object approach +class UserParams < StructuredParams::Params + attribute :name, :string + attribute :age, :integer + attribute :addresses, :array, value_class: AddressParams + + validates :name, presence: true +end +``` + +**Advantages of StructuredParams:** +- Focus on parameter handling rather than form rendering +- Automatic type casting with ActiveModel::Type +- Built-in Strong Parameters integration +- Cleaner syntax for API-first applications +- Better TypeScript/RBS integration + +## When to Choose StructuredParams + +Choose **StructuredParams** when you need: + +1. **Type-safe parameter handling** in Rails APIs +2. **Complex nested structures** with automatic casting +3. **Strong Parameters integration** without manual permit lists +4. **ActiveModel compatibility** for validations and serialization +5. **Enhanced error handling** with structured formats +6. **RBS type definitions** for better development experience + +## Migration Examples + +### From typed_params + +```ruby +# Before: typed_params +class UsersController < ApplicationController + typed_params do + param :user, type: Hash do + param :name, type: String, required: true + param :age, type: Integer + end + end + + def create + # Manual parameter extraction and validation + end +end + +# After: StructuredParams +class UserParams < StructuredParams::Params + attribute :name, :string + attribute :age, :integer + + validates :name, presence: true +end + +class UsersController < ApplicationController + def create + user_params = UserParams.new(params[:user]) + if user_params.valid? + User.create!(user_params.attributes) + else + render json: { errors: user_params.errors.to_hash } + end + end +end +``` + +### From dry-validation + +```ruby +# Before: dry-validation +UserContract = Dry::Validation.Contract do + params do + required(:name).filled(:string) + required(:age).filled(:integer) + end +end + +def create + result = UserContract.call(params[:user]) + if result.success? + User.create!(result.to_h) + else + render json: { errors: result.errors.to_h } + end +end + +# After: StructuredParams +class UserParams < StructuredParams::Params + attribute :name, :string + attribute :age, :integer + + validates :name, presence: true +end + +def create + user_params = UserParams.new(params[:user]) + if user_params.valid? + User.create!(user_params.attributes) + else + render json: { errors: user_params.errors.to_hash } + end +end +``` + +## Performance Considerations + +StructuredParams leverages ActiveModel::Type system, which provides: + +- **Efficient type casting** with built-in Rails optimizations +- **Memory-efficient validation** using ActiveModel's proven patterns +- **Lazy loading** of nested objects only when accessed +- **Cached permit lists** for Strong Parameters integration + +For high-throughput APIs, StructuredParams typically performs comparably to or better than manual parameter handling while providing significantly more features and type safety.