Building Forms with form_with
Fast recall
Quick revision
Core answer
form_with is Rails' current form builder for model-backed and standalone forms. With form_with model: @article, Rails uses model naming and persistence state to choose field names, the destination URL, and whether the submission creates or updates the record. The builder supplies helpers such as label, text_field, and submit, and Rails includes CSRF protection for applicable non-GET forms. The controller must still permit input, validate the model, and render validation messages deliberately.Whether you know form_with model: @post builds a form, f.text_field/f.submit, and it infers POST (new) vs PATCH (saved) from the record.
Forgetting form_with needs a model: (it infers the URL/verb), or naming fields that aren't in strong params (the value is dropped).
form_with model: @post builds a form (authenticity token, fields, route). f.text_field/f.text_area/f.submit. It infers POST (new) vs PATCH (saved) from the record.
Interview-ready guide
Interview answer
form_with is Rails' main form builder for model-backed and standalone forms. With <%= form_with model: @article do |form| %>, Rails uses the record's model name and persistence state to choose parameter names, a destination, and create-versus-update behaviour. Passing an explicit url and optional scope handles forms that are not tied to one record.
A new Article normally submits to the collection create route with POST. The same form given a persisted Article targets that member's update route and represents PATCH, using Rails' hidden method field where the browser needs it. This is why one _form.html.erb partial can serve both new and edit pages.
The yielded builder creates related controls such as form.label :title, form.text_field :title, and form.submit. Model-backed fields use names such as article[title], and the object supplies current values and validation errors. The form partial should display useful messages from article.errors when a save fails.
Rails adds an authenticity token to applicable non-GET forms for CSRF protection, but that does not make submitted attributes valid or permitted. The controller still filters the accepted shape and the model still validates domain rules. Render an invalid object with a failure status so its values and errors remain; redirect after a successful write.
Building Forms with form_with
Direct Answer
form_with is Rails' current form builder for model-backed and standalone forms. With form_with model: @article, Rails uses model naming and persistence state to choose field names, the destination URL, and whether the submission creates or updates the record. The builder supplies helpers such as label, text_field, and submit, and Rails includes CSRF protection for applicable non-GET forms. The controller must still permit input, validate the model, and render validation messages deliberately.
Deep Dive & Architecture
Model-backed form inference starts with Active Model conventions. The builder asks for the model name, parameter key, route key, and persistence state. That information connects an Article object to fields such as article[title] and to the appropriate route helper without duplicating those strings in the template.
Browsers submit name-value pairs, not Ruby objects. Rails parses those pairs into params, so the controller must select an allowed shape before mass assignment. A hidden method field lets an HTML form represent PATCH or DELETE semantics even though browsers directly support only GET and POST form methods.
The CSRF token connects the rendered form to the user's session and application origin checks. It protects against a different site causing an authenticated browser to submit an unwanted state-changing request. It does not validate prices, ownership, or any business field.
Error rendering completes the feedback loop. The failed model keeps rejected values and its errors collection in memory. Rendering within the same request preserves that state; redirecting creates a new request and usually loses it unless the application serialises it separately.
Code Example
<!-- app/views/articles/_form.html.erb -->
<%= form_with model: article do |form| %>
<% if article.errors.any? %>
<ul>
<% article.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
<% end %>
<%= form.label :title %>
<%= form.text_field :title %>
<%= form.submit %>
<% end %>
<!-- new.html.erb or edit.html.erb -->
<%= render 'form', article: @article %>
Common Mistakes & Pitfalls
Forgetting form_with needs a model: (it infers the URL/verb), or naming fields that aren't in strong params (the value is dropped).
Check your understanding
Answer these without looking back at the article.
- How does `form_with` choose POST or PATCH for a model?
- Why are CSRF tokens, strong parameters, and model validations separate protections?
- Why should an invalid form usually render instead of redirect?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.