From 9a586560debc5f7ec9d0e2a6c47f6dabc6ce90b5 Mon Sep 17 00:00:00 2001 From: mizuki-y Date: Fri, 10 Jul 2026 05:54:05 +0000 Subject: [PATCH 1/5] Refine README and installation copy --- README.md | 15 +++++++------ README_ja.md | 46 ++++++++++++++++++++------------------- docs/installation.md | 14 +++++++++++- structured_params.gemspec | 4 ++-- 4 files changed, 47 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index d9dd1b9..8d6c0b7 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,9 @@ English | [日本語](README_ja.md) -**Type-safe API parameter validation and form objects for Rails** +**Typed parameter objects and form objects for Rails.** + +Supports Ruby `3.2+` and Rails / ActiveModel `7.2` to `< 9.0`. StructuredParams solves these challenges: @@ -26,7 +28,7 @@ Built on ActiveModel, making nested objects and arrays easy to handle. # Installation gem 'structured_params' -# Initialize +# Register built-in structured types StructuredParams.register_types ``` @@ -44,7 +46,7 @@ class UserParams < StructuredParams::Params attribute :score, :integer attribute :tags, :array, value_type: :string # Primitive array attribute :address, :object, value_class: AddressParams # Nested object - + # validate raw string before type casting validates_raw :score, format: { with: /\A\d+\z/, message: 'must be numeric string' } validates :name, presence: true @@ -55,7 +57,7 @@ end # Use in API controller def create user_params = UserParams.new(params) - + if user_params.valid? User.create!(user_params.attributes) else @@ -77,7 +79,6 @@ end # params.permit(tags: []) ``` - ### 2. Form Object ```ruby @@ -85,7 +86,7 @@ class UserRegistrationForm < StructuredParams::Params attribute :name, :string attribute :email, :string attribute :terms_accepted, :boolean - + validates :name, :email, presence: true validates :terms_accepted, acceptance: true end @@ -95,7 +96,7 @@ end # Unlike API usage, form objects need require to scope to the correct key. def create form = UserRegistrationForm.new(UserRegistrationForm.permit(params)) - + if form.valid? User.create!(form.attributes) redirect_to root_path diff --git a/README_ja.md b/README_ja.md index 767e1f9..b4ee4d0 100644 --- a/README_ja.md +++ b/README_ja.md @@ -2,22 +2,24 @@ [English](README.md) | 日本語 -**Rails で型安全な API パラメータバリデーションとフォームオブジェクトを実現する gem** +**Rails の型付きパラメータオブジェクトとフォームオブジェクトを提供する gem。** + +対応範囲は Ruby `3.2+`、Rails / ActiveModel `7.2` 以上 `9.0` 未満です。 StructuredParams は、以下の課題を解決します: -- **API エンドポイント**: リクエストパラメータの型チェック・バリデーション・自動キャスト -- **フォームオブジェクト**: 複雑なフォーム入力の検証とモデルへの変換 +- **API エンドポイント**: リクエストパラメータの型チェック、バリデーション、型変換 +- **フォームオブジェクト**: 複雑なフォーム入力の検証とモデル変換 -ActiveModel をベースに、ネストしたオブジェクトや配列も簡単に扱えます。 +ActiveModel をベースに、ネストしたオブジェクトや配列も簡潔に扱えます。 -## 主な特徴 +## 主な機能 - ✅ **API パラメータバリデーション** - 型安全なリクエスト検証 -- ✅ **フォームオブジェクト** - 複雑なフォームロジックのカプセル化 -- ✅ **ネスト構造対応** - オブジェクトや配列を自動キャスト -- ✅ **Strong Parameters 統合** - permit リストを自動生成 -- ✅ **ActiveModel 互換** - バリデーション、シリアライゼーションなど標準機能をサポート +- ✅ **フォームオブジェクト** - 複雑なフォームロジックをカプセル化 +- ✅ **ネスト構造のサポート** - object / array の自動キャスト +- ✅ **Strong Parameters 連携** - permit リストの自動生成 +- ✅ **ActiveModel 互換** - バリデーション、シリアライズなど標準機能を利用可能 - ✅ **RBS 型定義** - 型安全な開発体験 ## クイックスタート @@ -26,7 +28,7 @@ ActiveModel をベースに、ネストしたオブジェクトや配列も簡 # インストール gem 'structured_params' -# 初期化 +# 組み込みの構造化型を登録 StructuredParams.register_types ``` @@ -44,7 +46,7 @@ class UserParams < StructuredParams::Params attribute :score, :integer attribute :tags, :array, value_type: :string # プリミティブ配列 attribute :address, :object, value_class: AddressParams # ネストオブジェクト - + # 型変換前の生文字列をバリデーション validates_raw :score, format: { with: /\A\d+\z/, message: 'must be numeric string' } validates :name, presence: true @@ -55,7 +57,7 @@ end # API コントローラーで使用 def create user_params = UserParams.new(params) - + if user_params.valid? User.create!(user_params.attributes) else @@ -73,7 +75,7 @@ class UserParams < StructuredParams::Params attribute :tags, :array, value_type: :string end -# 相当する Strong Parameters: +# Strong Parameters と同等: # params.permit(tags: []) ``` @@ -84,17 +86,18 @@ class UserRegistrationForm < StructuredParams::Params attribute :name, :string attribute :email, :string attribute :terms_accepted, :boolean - + validates :name, :email, presence: true validates :terms_accepted, acceptance: true end # コントローラーで使用 -# permit は params.require(:user_registration).permit(...) を内部で呼び出す +# permit は内部で params.require(:user_registration).permit(...) を呼びます。 # API と異なり、フォームオブジェクトでは require によるキー絞り込みが必要なため permit を使う + def create form = UserRegistrationForm.new(UserRegistrationForm.permit(params)) - + if form.valid? User.create!(form.attributes) redirect_to root_path @@ -107,18 +110,17 @@ end ## ドキュメント - **[インストールとセットアップ](docs/installation.md)** - StructuredParams の始め方 -- **[基本的な使用方法](docs/basic-usage.md)** - パラメータクラス、ネストオブジェクト、配列 -- **[バリデーション](docs/validation.md)** - ネスト構造での ActiveModel バリデーション使用 -- **[Strong Parameters](docs/strong-parameters.md)** - 自動 permit リスト生成 -- **[エラーハンドリング](docs/error-handling.md)** - フラットと構造化エラーフォーマット +- **[基本的な使い方](docs/basic-usage.md)** - パラメータクラス、ネストオブジェクト、配列 +- **[バリデーション](docs/validation.md)** - ネスト構造での ActiveModel バリデーション +- **[Strong Parameters](docs/strong-parameters.md)** - permit リストの自動生成 +- **[エラーハンドリング](docs/error-handling.md)** - フラット形式と構造化形式のエラー - **[シリアライゼーション](docs/serialization.md)** - パラメータのハッシュと JSON 変換 - **[フォームオブジェクト](docs/form-objects.md)** - Rails ビューとのフォームオブジェクトパターン - ## コントリビューション バグレポートやプルリクエストは GitHub の https://github.com/Syati/structured_params で歓迎しています。 ## ライセンス -この gem は [MIT License](https://opensource.org/licenses/MIT) の条件の下でオープンソースとして利用可能です。 +この gem は [MIT License](https://opensource.org/licenses/MIT) のもとで公開されています。 diff --git a/docs/installation.md b/docs/installation.md index 3911f18..c5e0bf3 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -36,7 +36,15 @@ Register the custom types in a Rails initializer: StructuredParams.register_types ``` -This registers the `:object` and `:array` types with ActiveModel::Type. +This registers the `:object` and `:array` types with `ActiveModel::Type`. + +The registration is explicit on purpose: + +- `:object` and `:array` are convenient names in application code +- They are also generic names, so auto-registering them at gem load time could silently collide with other code +- Keeping registration in an initializer makes the opt-in explicit and keeps custom aliases available when needed + +If you skip this step, `attribute :name, :object` and `attribute :name, :array` will not resolve in ActiveModel type lookup. ## Configuration @@ -54,6 +62,8 @@ StructuredParams.configure do |config| end ``` +If you only need configuration and want to avoid the default names, use `register_types_as(...)` first and then configure in the same initializer. + | Option | Default | Description | |--------|---------|-------------| | `array_index_base` | `0` | Index base for array elements in error messages (`0` or `1`) | @@ -77,3 +87,5 @@ class UserParams < StructuredParams::Params attribute :hobbies, :structured_array, value_class: HobbyParams end ``` + +Prefer custom names if your app or another gem already uses `:object` or `:array` in `ActiveModel::Type`. diff --git a/structured_params.gemspec b/structured_params.gemspec index e4e868a..aa5ee7f 100644 --- a/structured_params.gemspec +++ b/structured_params.gemspec @@ -9,8 +9,8 @@ Gem::Specification.new do |spec| spec.authors = ['Mizuki Yamamoto'] spec.email = ['mizuki-y@syati.info'] - spec.summary = 'Type-safe parameter validation and form objects for Rails.' - spec.description = '' + spec.summary = 'Typed parameter objects and form objects for Rails.' + spec.description = 'StructuredParams provides typed parameter objects for Rails APIs and forms, with nested object and array support, Strong Parameters integration, and raw-input validation via validates_raw.' spec.homepage = 'https://github.com/Syati/structured_params' spec.license = 'MIT' spec.required_ruby_version = '>= 3.2.0' From 81ed8e5806c86cdc1c3b2fc2c0d895dedaaffac6 Mon Sep 17 00:00:00 2001 From: mizuki-y Date: Sat, 11 Jul 2026 12:17:50 +0900 Subject: [PATCH 2/5] Update Ruby version to 4.0.5 and refine gemspec description formatting --- .codex/config.toml | 1 - .ruby-version | 2 +- structured_params.gemspec | 6 +++++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.codex/config.toml b/.codex/config.toml index 9d7012c..0d5a805 100644 --- a/.codex/config.toml +++ b/.codex/config.toml @@ -1,2 +1 @@ approval_policy = "on-request" -sandbox_mode = "workspace-write" diff --git a/.ruby-version b/.ruby-version index fcdb2e1..7636e75 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -4.0.0 +4.0.5 diff --git a/structured_params.gemspec b/structured_params.gemspec index aa5ee7f..0489492 100644 --- a/structured_params.gemspec +++ b/structured_params.gemspec @@ -10,7 +10,11 @@ Gem::Specification.new do |spec| spec.email = ['mizuki-y@syati.info'] spec.summary = 'Typed parameter objects and form objects for Rails.' - spec.description = 'StructuredParams provides typed parameter objects for Rails APIs and forms, with nested object and array support, Strong Parameters integration, and raw-input validation via validates_raw.' + spec.description = ( + 'StructuredParams provides typed parameter objects for Rails APIs and forms, ' \ + 'with nested object and array support, Strong Parameters integration, and ' \ + 'raw-input validation via validates_raw.' + ) spec.homepage = 'https://github.com/Syati/structured_params' spec.license = 'MIT' spec.required_ruby_version = '>= 3.2.0' From 22cb29a5735145c77ff1c8819f496d01f139145c Mon Sep 17 00:00:00 2001 From: mizuki-y Date: Sat, 11 Jul 2026 12:22:48 +0900 Subject: [PATCH 3/5] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8d6c0b7..a2d3256 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ English | [日本語](README_ja.md) **Typed parameter objects and form objects for Rails.** -Supports Ruby `3.2+` and Rails / ActiveModel `7.2` to `< 9.0`. +Supports Ruby `>= 3.2` and Rails / ActiveModel `>= 7.2, < 9.0`. StructuredParams solves these challenges: From 168c3d5ab3da225f0c9b95273cdd3522456d1943 Mon Sep 17 00:00:00 2001 From: mizuki-y Date: Sat, 11 Jul 2026 12:23:12 +0900 Subject: [PATCH 4/5] Update README and README_ja to clarify installation and configuration instructions --- README.md | 4 ++-- README_ja.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 8d6c0b7..37b3a6c 100644 --- a/README.md +++ b/README.md @@ -25,10 +25,10 @@ Built on ActiveModel, making nested objects and arrays easy to handle. ## Quick Start ```ruby -# Installation +# Gemfile gem 'structured_params' -# Register built-in structured types +# config/initializers/structured_params.rb StructuredParams.register_types ``` diff --git a/README_ja.md b/README_ja.md index b4ee4d0..fca7447 100644 --- a/README_ja.md +++ b/README_ja.md @@ -25,10 +25,10 @@ ActiveModel をベースに、ネストしたオブジェクトや配列も簡 ## クイックスタート ```ruby -# インストール +# Gemfile gem 'structured_params' -# 組み込みの構造化型を登録 +# config/initializers/structured_params.rb StructuredParams.register_types ``` From bf94ee0a101632927309f296bf7c8ad92a6c30a5 Mon Sep 17 00:00:00 2001 From: mizuki-y Date: Sat, 11 Jul 2026 03:39:49 +0000 Subject: [PATCH 5/5] Fix spec matcher for RuboCop --- spec/params_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/params_spec.rb b/spec/params_spec.rb index e1c38cd..dabb34e 100644 --- a/spec/params_spec.rb +++ b/spec/params_spec.rb @@ -417,7 +417,7 @@ context 'with default (en) locale' do it 'includes index in full_message' do full_messages = user_param.errors.map(&:full_message) - expect(full_messages).to include(match(/Hobbies 0 Name/)) + expect(full_messages).to include('Hobbies 0 Name can\'t be blank') end end