Form_with vs form_for in Rails: Key Differences and When to Use Each
form_for is the older Rails helper for building forms tied to a model, while form_with is the modern, unified helper introduced in Rails 5.1 that supports both model and non-model forms with better defaults and flexibility. form_with encourages remote forms by default and uses a simpler syntax.Quick Comparison
Here is a quick side-by-side comparison of form_for and form_with in Rails.
| Feature | form_for | form_with |
|---|---|---|
| Introduced in Rails version | Rails 2.0 | Rails 5.1 |
| Supports model forms | Yes | Yes |
| Supports non-model forms | No (requires manual setup) | Yes |
| Remote (AJAX) forms default | No (remote: true needed) | No (remote: true must be set explicitly) |
| Syntax style | Block with model object | Block with model or URL |
| HTML id and class defaults | Based on model name | More customizable and minimal |
Key Differences
form_for was designed specifically for forms tied to Active Record models. It automatically generates form fields based on the model's attributes and sets HTML element IDs and names accordingly. However, it does not support non-model forms easily and requires extra options for remote AJAX behavior.
form_with was introduced to unify form helpers and simplify form building. It supports both model-backed and plain URL forms with the same syntax. By default, form_with submits forms via standard HTTP requests (not AJAX) unless remote: true is specified. It also generates simpler HTML IDs and classes, making customization easier.
Another difference is that form_with uses keyword arguments and a more flexible API, encouraging cleaner and more consistent code. While form_for is still supported for legacy reasons, form_with is the recommended helper for new Rails applications.
Code Comparison
Here is how you create a form for a @post model using form_for:
<%= form_for @post do |f| %>
<%= f.label :title %>
<%= f.text_field :title %>
<%= f.label :body %>
<%= f.text_area :body %>
<%= f.submit "Save" %>
<% end %>form_with Equivalent
The equivalent form using form_with looks like this:
<%= form_with model: @post do |f| %>
<%= f.label :title %>
<%= f.text_field :title %>
<%= f.label :body %>
<%= f.text_area :body %>
<%= f.submit "Save" %>
<% end %>When to Use Which
Choose form_with for all new Rails projects because it is the modern, flexible helper that supports both model and non-model forms and uses AJAX when remote: true is specified. It leads to cleaner code and better user experience with less setup.
Use form_for only if you are maintaining legacy Rails code that already uses it extensively or if you need very specific behavior that form_with does not cover yet.
Key Takeaways
form_with is the modern, recommended form helper in Rails 5.1+.form_for is older and model-specific, while form_with supports both model and non-model forms.form_with submits forms via standard HTTP requests by default; use remote: true for AJAX.form_with for new projects and form_for only for legacy support.form_with has a cleaner, more flexible syntax with keyword arguments.