Ror Forms
title: Ruby on Rails Forms — Complete Guide to Form Building description: 'Learn Ruby on Rails forms: form_with, form helpers, nested forms, file uploads, validation display, Turbo Frames, and form best practices.' date: 2026-06-28 lastmod: 2026-06-28 weight: 22 tags: [backend, ror]
Rails forms use form_with to generate HTML forms bound to models, with helpers for text fields, selects, checkboxes, date pickers, file uploads, and nested attributes.
## What You'll Learn
By the end of this tutorial, you'll create model-bound forms with form_with, use form helpers for various input types, handle file uploads, display validation errors, implement nested forms, and use Turbo for AJAX.
## Real-World Use
A registration form collects username, email, password (with confirmation), accepts terms, and uploads an avatar. Validation errors display inline. Turbo handles submission without full page reload.
## Forms Learning Path
```mermaid
flowchart LR
A[Associations] --> B[Forms]
B --> C[Authentication]
C --> D[Authorization]
D --> E[API]
B --> F{You Are Here}
style F fill:#f90,color:#fff
Basic Form
<%= form_with model: @post, local: true do |form| %>
<% if @post.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@post.errors.count, "error") %></h2>
<ul>
<% @post.errors.each do |error| %>
<li><%= error.full_message %></li>
<% end %>
</ul>
</div>
<% end %>
<div>
<%= form.label :title %>
<%= form.text_field :title, class: "form-control" %>
</div>
<div>
<%= form.label :body %>
<%= form.text_area :body, rows: 10, class: "form-control" %>
</div>
<div>
<%= form.label :published %>
<%= form.check_box :published %>
</div>
<%= form.submit class: "btn btn-primary" %>
<% end %>
Form Helpers
<!-- Text inputs -->
<%= form.text_field :username %>
<%= form.email_field :email %>
<%= form.password_field :password %>
<%= form.number_field :age, min: 0, max: 150 %>
<%= form.phone_field :phone %>
<%= form.url_field :website %>
<!-- Selection -->
<%= form.select :role, ["user", "admin", "moderator"] %>
<%= form.select :category_id, Category.pluck(:name, :id) %>
<%= form.collection_select :category_id, Category.all, :id, :name %>
<%= form.radio_button :role, "admin" %> Admin
<%= form.check_box :terms %> I agree
<!-- Date and time -->
<%= form.date_field :birthday %>
<%= form.datetime_field :starts_at %>
<%= form.time_field :opens_at %>
File Upload
<%= form_with model: @user, multipart: true do |form| %>
<%= form.label :avatar %>
<%= form.file_field :avatar, accept: "image/*" %>
<% if @user.avatar.attached? %>
<%= image_tag @user.avatar.variant(:thumb) %>
<% end %>
<% end %>
class User < ApplicationRecord
has_one_attached :avatar
end
class UsersController < ApplicationController
def create
@user = User.new(user_params)
if @user.save
redirect_to @user
else
render :new, status: :unprocessable_entity
end
end
private
def user_params
params.require(:user).permit(:name, :email, :avatar)
end
end
Nested Forms
class Invoice < ApplicationRecord
has_many :line_items, dependent: :destroy
accepts_nested_attributes_for :line_items, allow_destroy: true,
reject_if: :all_blank
end
<%= form_with model: @invoice do |form| %>
<%= form.fields_for :line_items do |item_form| %>
<div class="nested-fields">
<%= item_form.text_field :description %>
<%= item_form.number_field :quantity %>
<%= item_form.number_field :unit_price, step: 0.01 %>
<%= item_form.check_box :_destroy %> Remove
</div>
<% end %>
<% end %>
Common Mistakes
1. Not Using form_with's Model Binding
form_with @model generates correct action URL, method, and CSRF token automatically.
2. Missing multipart: true for File Uploads
File upload forms need multipart: true option or the file won't be sent.
3. Not Displaying Validation Errors
Without error display, users don't know what's wrong. Use @model.errors.any? and @model.errors.full_messages.
4. Forgetting Strong Parameters for Nested Attributes
Nested attributes need explicit permit: params.permit(line_items: [:description, :quantity, :_destroy]).
5. Using form_tag Instead of form_with
form_tag (Rails 5 style) is outdated. Use form_with for all new forms (it works with and without models).
Practice Questions
1. What is form_with?
The standard Rails form builder. form_with model: @post binds to a model, generating proper action, method, and CSRF token.
2. How do you handle file uploads in forms?
Set multipart: true on the form, use form.file_field, and the model must have file attachment (Active Storage).
3. What are nested attributes?
accepts_nested_attributes_for allows creating/updating associated records through the parent form.
4. How do you display validation errors in a form?
Check @model.errors.any? and iterate @model.errors.full_messages or use field-level @model.errors[:attribute].
5. Challenge: Create a registration form with username, email, password, password confirmation, and terms acceptance.
<%= form_with model: @user do |f| %>
<%= f.text_field :username %>
<%= f.email_field :email %>
<%= f.password_field :password %>
<%= f.password_field :password_confirmation %>
<%= f.check_box :terms %> I agree to the terms
<%= f.submit "Register" %>
<% end %>
FAQ
Mini Project: Registration Form
Create a complete user registration form with validation errors and all field types.
<%= form_with model: @user, local: true do |f| %>
<%= render "shared/errors", object: @user %>
<%= f.label :username %><%= f.text_field :username, required: true %>
<%= f.label :email %><%= f.email_field :email %>
<%= f.label :password %><%= f.password_field :password %>
<%= f.label :password_confirmation %><%= f.password_field :password_confirmation %>
<%= f.label :birthday %><%= f.date_field :birthday %>
<%= f.label :country %><%= f.select :country, ["US", "UK", "CA"] %>
<%= f.label :avatar %><%= f.file_field :avatar %>
<%= f.label :terms %><%= f.check_box :terms %> I agree
<%= f.submit "Create Account", class: "btn btn-primary" %>
<% end %>
What's Next
Ruby on Rails Authentication Ruby on Rails Authorization
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro