Skip to content

Extract form object behavior#20

Open
Syati wants to merge 6 commits into
mainfrom
refactor-form-object
Open

Extract form object behavior#20
Syati wants to merge 6 commits into
mainfrom
refactor-form-object

Conversation

@Syati

@Syati Syati commented Jul 12, 2026

Copy link
Copy Markdown
Owner

Summary

Extract form-object-specific behavior from StructuredParams::Params into an ActiveSupport::Concern.

Params retains shared model naming, typed parameter handling, validation, and serialization. This preserves the existing Form, Parameter, and Parameters naming behavior while isolating Rails form helper and nested form-root handling.

Validation

  • bundle exec rubocop --no-server lib/structured_params.rb lib/structured_params/params.rb lib/structured_params/form_object.rb spec/form_object_spec.rb spec/permit_spec.rb
  • bundle exec rbs-inline --output=sig lib/**/*.rb
  • bundle exec steep check
  • bundle exec rspec

Summary by CodeRabbit

  • New Features

    • Added form-object integration for Rails form helpers, including model_name, to_model, and persistence behavior.
    • Form-suffixed classes now use the corresponding model name for form and i18n handling.
    • Improved nested parameter detection and strong-parameter processing.
  • Documentation

    • Updated form-object and strong-parameter guidance to reflect the new naming and parameter-key behavior.
  • Bug Fixes

    • Classes ending in Parameter or Parameters now retain their default ActiveModel naming and i18n keys.

@coderabbitai

coderabbitai Bot commented Jul 12, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 7bcef00a-448e-45c4-b166-af1da191535e

📥 Commits

Reviewing files that changed from the base of the PR and between 7166757 and 84ed1ab.

📒 Files selected for processing (12)
  • docs/form-objects.md
  • docs/strong-parameters.md
  • lib/structured_params.rb
  • lib/structured_params/form_object.rb
  • lib/structured_params/params.rb
  • sig/structured_params/form_object.rbs
  • sig/structured_params/params.rbs
  • spec/form_object_spec.rb
  • spec/i18n_spec.rb
  • spec/params_spec.rb
  • spec/permit_spec.rb
  • spec/support/locales/ja.yml

📝 Walkthrough

Walkthrough

Changes

Form Object Behavior

Layer / File(s) Summary
Form object concern and contracts
lib/structured_params/form_object.rb, sig/structured_params/form_object.rbs
Adds shared Rails form integration, Form-suffix model naming, nested parameter-shape checks, and RBS declarations.
Params integration and type surface
lib/structured_params.rb, lib/structured_params/params.rb, sig/structured_params/params.rbs
Includes and loads FormObject, moves parameter preprocessing to the concern, and removes duplicated methods and signatures.
Documentation and behavioral coverage
docs/*.md, spec/*, spec/support/locales/ja.yml
Updates parameter-key and i18n documentation, tests, and locale keys for default non-Form naming behavior.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Request
  participant UserParams
  participant FormObject
  participant ActiveModel
  Request->>UserParams: provide parameter hash
  UserParams->>FormObject: evaluate nested parameter requirement
  FormObject->>ActiveModel: resolve model_name.param_key
  ActiveModel-->>UserParams: return parameter key
  UserParams-->>Request: permit and convert parameters
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: extracting form-object-specific behavior into a separate concern.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor-form-object

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Syati added 5 commits July 12, 2026 15:51
Move model_name and form_class? into the FormObject concern so the
custom "Parameters"/"Parameter"/"Form" suffix-stripping naming lives
alongside the other form-only logic that depends on it
(require_nested_parameters?, matches_model_name?). Non-Form Params
subclasses now fall back to ActiveModel's default model_name (based
on the class's own name) instead of having a suffix silently removed,
making param_key/i18n_key resolution predictable without needing to
mentally track which suffix was stripped.

This is a breaking change for non-Form Parameters/Parameter classes:
their model_name, param_key, and i18n_key now reflect the full class
name (e.g. UserParameter -> "user_parameter" instead of "user").
Updated specs and locale fixtures accordingly.
process_action_controller_parameters now checks form_class? itself
before deferring to FormObject#require_nested_parameters?, instead of
require_nested_parameters? checking it internally. This makes the
Params/FormObject boundary visible at the call site: reading
process_action_controller_parameters alone tells you FormObject's
logic is only consulted for Form classes, without having to jump into
form_object.rb to learn that.
The method was down to two lines and had exactly one caller, so fold
it into process_input_parameters's ActionController::Parameters
branch instead of keeping a single-use indirection.
docs/form-objects.md and docs/strong-parameters.md still documented
the old behavior where Parameters/Parameter suffixes were also
stripped from model_name. Update the examples and i18n locale keys to
match the current Form-only scoping.
@Syati Syati marked this pull request as ready for review July 12, 2026 22:51
Copilot AI review requested due to automatic review settings July 12, 2026 22:51

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 84ed1ab941

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

name_without_suffix = name.sub(/Form$/, '')
ActiveModel::Name.new(self, namespace, name_without_suffix)
else
super

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve Parameter suffix stripping in model_name

For existing StructuredParams::Params subclasses named ...Parameter or ...Parameters, this super path now falls back to ActiveModel's default name instead of the previous name.sub(/(Parameters?|Form)$/, '') behavior. Because permit still derives its required root from model_name.param_key, calls such as UserParameter.permit(params) now require :user_parameter instead of the previously supported :user, breaking existing controllers and i18n scopes that followed the documented suffix convention.

Useful? React with 👍 / 👎.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors StructuredParams::Params by extracting Rails form-object-specific behavior into a new StructuredParams::FormObject ActiveSupport::Concern, and updates tests/docs/signatures to match the resulting model_name / param_key behavior.

Changes:

  • Added StructuredParams::FormObject concern and mixed it into StructuredParams::Params.
  • Adjusted model_name customization to apply only to Form-suffixed classes (and updated specs/docs accordingly).
  • Updated i18n fixtures/overrides and regenerated sig/ outputs to reflect the new behavior.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
spec/support/locales/ja.yml Updates attribute translation scopes to match new model_name.i18n_key values.
spec/permit_spec.rb Updates nested root key in params hashes to match new param_key behavior.
spec/params_spec.rb Updates i18n override keys for nested error messages.
spec/i18n_spec.rb Updates i18n override keys used in translation resolution tests.
spec/form_object_spec.rb Updates expectations around suffix stripping / model_name behavior.
sig/structured_params/params.rbs Updates generated signature to reflect extracted concern + removed methods.
sig/structured_params/form_object.rbs New generated signature for the concern.
lib/structured_params/params.rb Includes the concern and routes ActionController::Parameters handling through it.
lib/structured_params/form_object.rb New concern holding form helper methods + nested-params require heuristics + model_name override.
lib/structured_params.rb Requires ActiveSupport concern and the new form_object file.
docs/strong-parameters.md Updates examples/explanations for permit key selection (param_key).
docs/form-objects.md Updates class-name conventions and i18n key examples.

Comment on lines +170 to +171
require = self.class.form_class? && require_nested_parameters?(params)
self.class.permit(params, require: require).to_h
Comment thread spec/form_object_spec.rb
Comment on lines 222 to 233
describe 'class name with "Parameters" suffix' do
it 'removes "Parameters" suffix from model_name' do
expect(OrderParameters.model_name.name).to eq('Order')
expect(OrderParameters.model_name.param_key).to eq('order')
it 'keeps the default ActiveModel model_name (no suffix removal outside Form classes)' do
expect(OrderParameters.model_name.name).to eq('OrderParameters')
expect(OrderParameters.model_name.param_key).to eq('order_parameters')
end
end

describe 'class name with "Parameter" suffix' do
it 'removes "Parameter" suffix from model_name' do
expect(PaymentParameter.model_name.name).to eq('Payment')
expect(PaymentParameter.model_name.param_key).to eq('payment')
it 'keeps the default ActiveModel model_name (no suffix removal outside Form classes)' do
expect(PaymentParameter.model_name.name).to eq('PaymentParameter')
expect(PaymentParameter.model_name.param_key).to eq('payment_parameter')
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants