RoR Forms and Form Helpers

Forms let users send data to your Rails application. Every signup page, login form, search box, and settings panel is a form. Rails provides form helpers — Ruby methods that generate the correct HTML form elements and wire them to your models automatically.

The form_with Helper

form_with is the main Rails form builder. Pass it a model object and it generates a form that points to the correct URL and uses the correct HTTP method.

<%= form_with model: @article do |f| %>
  <%= f.label :title %>
  <%= f.text_field :title %>

  <%= f.label :body %>
  <%= f.text_area :body %>

  <%= f.submit "Save Article" %>
<% end %>

Rails generates different HTML depending on whether @article is a new record or an existing one:

New record (@article.new_record? = true):
  <form action="/articles" method="post">

Existing record (@article.persisted? = true):
  <form action="/articles/3" method="post">
    <input type="hidden" name="_method" value="patch">

You write the same form code for both new and edit pages. Rails handles the difference automatically.

Form Input Types

Text inputs:
  <%= f.text_field :name %>          ← single line text
  <%= f.text_area :body %>           ← multi-line text
  <%= f.password_field :password %>  ← masked input
  <%= f.email_field :email %>        ← email with validation hint
  <%= f.number_field :age %>         ← numeric keyboard on mobile
  <%= f.url_field :website %>        ← URL with validation hint
  <%= f.search_field :query %>       ← search input

Selection inputs:
  <%= f.check_box :published %>      ← true/false checkbox
  <%= f.radio_button :status, "active" %>    ← one of many
  <%= f.select :category, ["books", "tech", "food"] %>  ← dropdown
  <%= f.collection_select :user_id, User.all, :id, :name %>  ← dropdown from DB

Date and time:
  <%= f.date_field :birthday %>
  <%= f.datetime_local_field :scheduled_at %>
  <%= f.time_field :meeting_time %>

File:
  <%= f.file_field :avatar %>

Labels

Always pair each input with a label. Labels improve accessibility and let users click the label text to focus the input.

<%= f.label :email, "Your Email Address" %>
<%= f.email_field :email %>

Generates:
<label for="user_email">Your Email Address</label>
<input type="email" name="user[email]" id="user_email">

A Complete Registration Form

app/views/users/new.html.erb

<h1>Create Your Account</h1>

<% if @user.errors.any? %>
  <ul>
    <% @user.errors.full_messages.each do |msg| %>
      <li><%= msg %></li>
    <% end %>
  </ul>
<% end %>

<%= form_with model: @user do |f| %>
  <p>
    <%= f.label :name, "Full Name" %>
    <%= f.text_field :name, placeholder: "Jane Doe" %>
  </p>

  <p>
    <%= f.label :email %>
    <%= f.email_field :email, placeholder: "you@example.com" %>
  </p>

  <p>
    <%= f.label :password %>
    <%= f.password_field :password %>
  </p>

  <p>
    <%= f.label :password_confirmation, "Confirm Password" %>
    <%= f.password_field :password_confirmation %>
  </p>

  <%= f.submit "Create Account" %>
<% end %>

How Form Data Reaches the Controller

Form field name:  user[email]
                     |
                     v
Controller params: params[:user][:email]
                     |
                     v
Strong parameters: params.require(:user).permit(:name, :email, :password)
                     |
                     v
Model: User.new(user_params)

Select Dropdowns

Simple array options:
<%= f.select :country, ["USA", "Canada", "UK", "India"] %>

Array with labels and values:
<%= f.select :role, [["Admin", "admin"], ["Editor", "editor"], ["Viewer", "viewer"]] %>

Include a blank option:
<%= f.select :category, ["Books", "Tech"], include_blank: "-- Choose a Category --" %>

Populate from database:
<%= f.collection_select :author_id, Author.all, :id, :name,
    { include_blank: "Select Author" } %>

Checkboxes and Radio Buttons

Single checkbox (boolean field):
<%= f.check_box :newsletter_opt_in %>
<%= f.label :newsletter_opt_in, "Send me the newsletter" %>

Multiple checkboxes (store as array):
<% ["Ruby", "Python", "JavaScript"].each do |lang| %>
  <%= check_box_tag "user[languages][]", lang %>
  <%= label_tag lang %>
<% end %>

Radio buttons:
<%= f.radio_button :plan, "free" %> <%= f.label :plan_free, "Free" %>
<%= f.radio_button :plan, "pro" %>  <%= f.label :plan_pro, "Pro" %>

Forms Without a Model

Use form_with url: when you need a form that does not map to a model — like a search form:

<%= form_with url: search_path, method: :get do |f| %>
  <%= f.label :q, "Search" %>
  <%= f.search_field :q, placeholder: "Type to search..." %>
  <%= f.submit "Search" %>
<% end %>

The search term arrives in params[:q]. Use method: :get so the search query appears in the URL, which lets users share and bookmark search results.

Form Submission Flow

User fills in form and clicks Submit
        |
        v
Browser sends HTTP POST to /users
  with body: user[name]=Alice&user[email]=alice@x.com
        |
        v
Router: POST /users → UsersController#create
        |
        v
Controller reads params, calls User.new(user_params)
        |
        v
Validations run
        |
        +-- Pass → record saved → redirect to profile page
        +-- Fail → render :new → form reappears with errors shown

Rails form helpers reduce the amount of HTML you write, handle CSRF tokens automatically, and keep your forms synchronized with your models.

Leave a Comment

Your email address will not be published. Required fields are marked *