Skip to content

Ror Forms

DodaTech 4 min read

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

What is the difference between form_for and form_with?

form_for is deprecated. form_with is the current standard. It works for both model-bound and standalone forms.

How do I create AJAX forms in Rails?

form_with defaults to remote: true (Turbo). Submission happens via AJAX without full page reload.

What is fields_for?

Used for nested forms. Renders form fields for an associated model (e.g., line items within an invoice).

How do I add placeholder text to a field?

form.text_field :search, placeholder: 'Search...'.

How do I create a search form?

form_with url: search_path, method: :get, local: true do |f| f.text_field :q end.

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