Rails Form Helpers
Rails provides powerful form helpers that make building forms easy and secure. They automatically handle CSRF protection, model binding, and error display.
form_with Helper
The modern way to create forms in Rails:
erb
1<!-- Resource-based form (for model) -->
2<%= form_with model: @article do |form| %>
3 <%= form.text_field :title %>
4 <%= form.text_area :body %>
5 <%= form.submit %>
6<% end %>
7
8<!-- URL-based form -->
9<%= form_with url: search_path, method: :get do |form| %>
10 <%= form.text_field :query %>
11 <%= form.submit "Search" %>
12<% end %>Generated HTML
html
1<form action="/articles" method="post" data-turbo="true">
2 <input type="hidden" name="authenticity_token" value="..." />
3 <input type="text" name="article[title]" id="article_title" />
4 <textarea name="article[body]" id="article_body"></textarea>
5 <input type="submit" value="Create Article" />
6</form>Common Form Fields
Text Fields
erb
1<%= form_with model: @user do |f| %>
2 <!-- Basic text field -->
3 <%= f.text_field :name %>
4
5 <!-- With placeholder and class -->
6 <%= f.text_field :name, placeholder: "Enter name", class: "form-control" %>
7
8 <!-- Email field -->
9 <%= f.email_field :email %>
10
11 <!-- Password field -->
12 <%= f.password_field :password %>
13
14 <!-- Hidden field -->
15 <%= f.hidden_field :referrer, value: "homepage" %>
16
17 <!-- Phone field -->
18 <%= f.telephone_field :phone %>
19
20 <!-- URL field -->
21 <%= f.url_field :website %>
22
23 <!-- Number field -->
24 <%= f.number_field :age, min: 0, max: 120 %>
25
26 <!-- Range field -->
27 <%= f.range_field :rating, min: 1, max: 5 %>
28<% end %>Text Areas
erb
1<%= f.text_area :body %>
2<%= f.text_area :body, rows: 10, cols: 50 %>
3<%= f.text_area :body, size: "50x10" %>
4<%= f.text_area :description, class: "rich-editor", data: { controller: "editor" } %>Select Fields
erb
1<!-- Basic select -->
2<%= f.select :category, ["Technology", "Sports", "Music"] %>
3
4<!-- With blank option -->
5<%= f.select :category, ["Technology", "Sports", "Music"],
6 include_blank: "Select a category" %>
7
8<!-- With prompt -->
9<%= f.select :category, ["Technology", "Sports", "Music"],
10 prompt: "Choose one..." %>
11
12<!-- From collection -->
13<%= f.collection_select :category_id, Category.all, :id, :name %>
14
15<!-- With selected value -->
16<%= f.select :status, [["Draft", "draft"], ["Published", "published"]],
17 selected: "draft" %>
18
19<!-- Grouped options -->
20<%= f.grouped_collection_select :city_id, Country.all, :cities, :name, :id, :name %>Checkboxes and Radio Buttons
erb
1<!-- Single checkbox -->
2<%= f.check_box :terms_accepted %>
3<%= f.label :terms_accepted, "I accept the terms" %>
4
5<!-- Checkbox with custom values -->
6<%= f.check_box :active, {}, "yes", "no" %>
7
8<!-- Multiple checkboxes from collection -->
9<%= f.collection_check_boxes :tag_ids, Tag.all, :id, :name do |b| %>
10 <div class="checkbox">
11 <%= b.check_box %>
12 <%= b.label %>
13 </div>
14<% end %>
15
16<!-- Radio buttons -->
17<%= f.radio_button :gender, "male" %>
18<%= f.label :gender_male, "Male" %>
19<%= f.radio_button :gender, "female" %>
20<%= f.label :gender_female, "Female" %>
21
22<!-- Radio from collection -->
23<%= f.collection_radio_buttons :role_id, Role.all, :id, :name do |b| %>
24 <div class="radio">
25 <%= b.radio_button %>
26 <%= b.label %>
27 </div>
28<% end %>Date and Time Fields
erb
1<!-- Date field (HTML5) -->
2<%= f.date_field :birth_date %>
3
4<!-- Time field -->
5<%= f.time_field :start_time %>
6
7<!-- Datetime field -->
8<%= f.datetime_local_field :published_at %>
9
10<!-- Date select (Rails dropdowns) -->
11<%= f.date_select :birth_date, start_year: 1900, end_year: Date.today.year %>
12
13<!-- Time select -->
14<%= f.time_select :start_time, minute_step: 15 %>
15
16<!-- Datetime select -->
17<%= f.datetime_select :event_at %>File Uploads
erb
1<!-- File field -->
2<%= f.file_field :avatar %>
3
4<!-- Multiple files -->
5<%= f.file_field :documents, multiple: true %>
6
7<!-- With accept type -->
8<%= f.file_field :image, accept: "image/*" %>Labels
erb
1<%= f.label :name %>
2<!-- <label for="user_name">Name</label> -->
3
4<%= f.label :name, "Full Name" %>
5<!-- <label for="user_name">Full Name</label> -->
6
7<%= f.label :name, class: "form-label" %>
8
9<%= f.label :name do %>
10 <strong>Name</strong> <small>(required)</small>
11<% end %>Form Options
erb
1<%= form_with model: @article,
2 local: true, # Disable Turbo/AJAX
3 url: custom_path, # Custom URL
4 method: :patch, # HTTP method
5 class: "my-form", # CSS class
6 id: "article-form", # HTML ID
7 data: { turbo: false }, # Disable Turbo
8 html: { novalidate: true } do |f| %>
9<% end %>Nested Attributes
For associated models:
ruby
1# Model
2class Article < ApplicationRecord
3 has_many :comments
4 accepts_nested_attributes_for :comments,
5 allow_destroy: true,
6 reject_if: :all_blank
7enderb
1<%= form_with model: @article do |f| %>
2 <%= f.text_field :title %>
3
4 <h3>Comments</h3>
5 <%= f.fields_for :comments do |comment_form| %>
6 <div class="comment-fields">
7 <%= comment_form.text_area :body %>
8 <%= comment_form.check_box :_destroy %>
9 <%= comment_form.label :_destroy, "Remove" %>
10 </div>
11 <% end %>
12
13 <%= f.submit %>
14<% end %>Displaying Validation Errors
erb
1<%= form_with model: @user do |f| %>
2 <% if @user.errors.any? %>
3 <div class="error-messages">
4 <h2><%= pluralize(@user.errors.count, "error") %> prevented saving:</h2>
5 <ul>
6 <% @user.errors.full_messages.each do |message| %>
7 <li><%= message %></li>
8 <% end %>
9 </ul>
10 </div>
11 <% end %>
12
13 <div class="field <%= 'has-error' if @user.errors[:name].any? %>">
14 <%= f.label :name %>
15 <%= f.text_field :name %>
16 <% if @user.errors[:name].any? %>
17 <span class="error"><%= @user.errors[:name].first %></span>
18 <% end %>
19 </div>
20<% end %>Form Styling with Tailwind
erb
1<%= form_with model: @user, class: "space-y-6" do |f| %>
2 <div>
3 <%= f.label :name, class: "block text-sm font-medium text-gray-700" %>
4 <%= f.text_field :name,
5 class: "mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500" %>
6 </div>
7
8 <div>
9 <%= f.label :email, class: "block text-sm font-medium text-gray-700" %>
10 <%= f.email_field :email,
11 class: "mt-1 block w-full rounded-md border-gray-300 shadow-sm" %>
12 </div>
13
14 <%= f.submit "Save",
15 class: "inline-flex justify-center rounded-md border border-transparent bg-indigo-600 py-2 px-4 text-sm font-medium text-white shadow-sm hover:bg-indigo-700" %>
16<% end %>Forms are a core part of Rails applications - master these helpers!
