diff --git a/README.md b/README.md index 3ffad23..1ef40af 100644 --- a/README.md +++ b/README.md @@ -227,6 +227,11 @@ f.Checkbox(:terms) ; f.Toggle(:notify) ; f.FileInput(:avatar) f.Label(:email) ; f.Hidden(:token) ; f.submit("Save", :primary) ``` +Migrating from Rails' `FormBuilder`? `f.hidden_field(:token, value: x)` is a +snake_case alias for `f.Hidden` — same model-bound path, and an explicit +`value:` wins over the model's current value — so those call sites port over +verbatim. + For a bespoke widget (date picker, tag field, remote select), wrap it in `f.Control` and bind through the public helpers — this is the supported path, not a fork reason: diff --git a/lib/phlex_forms/builder.rb b/lib/phlex_forms/builder.rb index a5cdb7c..7e40a09 100644 --- a/lib/phlex_forms/builder.rb +++ b/lib/phlex_forms/builder.rb @@ -175,6 +175,13 @@ def Hidden(name, **) render field_object(name).hidden(**) end + # Rails FormBuilder-compatible hidden field, for straight migration of + # `form.hidden_field(:token, value: x)` call sites. Same model-bound path as + # `Hidden`; an explicit `value:` wins over the model's current value. + def hidden_field(name, **) + render field_object(name).hidden(**) + end + def Label(name, text = nil, *modifiers, **, &) render field_object(name).label(text, *modifiers, **, &) end diff --git a/spec/forms/components_spec.rb b/spec/forms/components_spec.rb index 2ac480e..57179e7 100644 --- a/spec/forms/components_spec.rb +++ b/spec/forms/components_spec.rb @@ -65,6 +65,41 @@ def render_form_via(model, **args, &block) end end + describe "hidden_field (Rails FormBuilder migration aid)" do + it "renders a scoped hidden input with an explicit value: override" do + user = build_model(:user, name: "Ada") + + output = render_form(user) do |f| + f.hidden_field(:accepted_terms_document_id, value: 42) + end + + expect(output).to include('type="hidden"') + expect(output).to include('name="user[accepted_terms_document_id]"') + expect(output).to include('id="user_accepted_terms_document_id"') + expect(output).to include('value="42"') + end + + it "binds the value from the model when none is passed" do + user = build_model(:user, token: "abc123") + + output = render_form(user) { |f| f.hidden_field(:token) } + + expect(output).to include('type="hidden"') + expect(output).to include('name="user[token]"') + expect(output).to include('value="abc123"') + end + + it "renders under the plain theme too (bare hidden input)" do + user = build_model(:user, token: "abc123") + + output = render_form(user, theme: :plain) { |f| f.hidden_field(:token) } + + expect(output).to include('