Formtastic forms in Rails for Beginners

Published: 2015-01- 8

You will build a lot of forms in Rails and Formtastic is a gem that will help speed up your form creation. This enables you to have great forms with a lot of extras in the same amount of time it takes to create a basic from in Rails.

Formtastic code is very similar to the standard Rails form code though it will generate more relevant HTML that can be used to make your forms more useable.

This article will go over getting started with Formtastic in Rails as a beginner, covering the basic types of form elements. Formtastic's fantastic readme is essential reading, though I hope I can ease beginners into the process of getting started.

Prerequisites

You will need a basic understanding of model validations and Active record associations which has been covered in previous articles.

You should have a solid understanding of how to build forms in Rails. You can always review my Rails forms for Beginners article to help bring you up to speed.

The Setup

All the examples in the article will be built and tested using the following versions:
  • Rails: 4.1.8
  • Ruby 2.1.5
  • Formtastic 3.1.2
  • MiniTest 5.4.3

Installing Formtastic

The standard: add the gem to your Gemfile and run bundle to install it

gem 'formtastic', '~> 3.1'

Run the Formtastic generator, to install the Formtastic template into your app. This is a one time only step.

rails generate formtastic:install

Formtastic comes with some default css styles that are great for starting out.

Add the following lines to: app/assets/stylesheets/application.css

  *= require formtastic
  *= require my_formtastic_changes

You will need to generate a blank app/assets/stylesheets/my_formtastic_changes.css file. You can do this on Mac/Linux with the bash command:

touch app/assets/stylesheets/my_formtastic_changes.css

See the Formtastic Readme if you require IE6/7 support for further steps.

Generate a Scaffold

To start using Formtastic, you just have to generate your standard Rails scaffold using the exact same syntax as before. Here is an example with a Article model.

rails generate scaffold Article title:string body:text

The generated file app/views/posts/_form.html.erb will look a little different to before.

<%= semantic_form_for @article do |f| %>
  <%= f.inputs do %>
    <%= f.input :title %>
    <%= f.input :body %>
  <% end %>

  <%= f.actions do %>
    <%= f.action :submit, :as => :input %>
  <% end %>
<% end %>

This is how a standard Rails scaffold form looks. Formtastic might look like less, but it does so much more.

<%= form_for(@article) do |f| %>
  <% if @article.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@article.errors.count, "error") %> 
       prohibited this article from being saved:</h2>

      <ul>
      <% @article.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= f.label :title %><br>
    <%= f.text_field :title %>
  </div>
  <div class="field">
    <%= f.label :body %><br>
    <%= f.text_area :body %>
  </div>
  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

Lets look at the generated HTML

Formtastic HTML

<form accept-charset="UTF-8" action="/articles" class="formtastic article" 
id="new_article" method="post" novalidate="novalidate">
<div style="display:none"><input name="utf8" type="hidden" value="&#x2713;" />
<input name="authenticity_token" type="hidden" value="N/eg6LfW/w=" />
</div>
<fieldset class="inputs"><ol>
  <li class="string input optional stringish" id="article_title_input">
    <label class="label" for="article_title">Title</label>
    <input id="article_title" maxlength="255" name="article[title]" type="text" />
  </li>
  <li class="text input optional" id="article_body_input">
    <label class="label" for="article_body">Body</label>
    <textarea id="article_body" name="article[body]" rows="20"> </textarea>
  </li>
</ol></fieldset>
<fieldset class="actions"><ol>
  <li class="action input_action " id="article_submit_action">
    <input name="commit" type="submit" value="Create Article" />
  </li>
</ol></fieldset>
</form>

As you can see, everything is wrapped in fieldset, ol and li tags with id and label tags for each input field. This gives Formtastic a lot of powerful ways to use css for styling which we will see later.

Rails scaffold HTML

<form accept-charset="UTF-8" action="/articles" class="new_article" id="new_article" method="post">
  <div style="display:none">
  <input name="utf8" type="hidden" value="&#x2713;" />
  <input name="authenticity_token" type="hidden" value="/1iuG++UmXpoeu55MMKwozGA=" />
  </div>
  <div class="field">
    <label for="article_title">Title</label><br>
    <input id="article_title" name="article[title]" type="text" />
  </div>
  <div class="field">
    <label for="article_body">Body</label><br>
    <textarea id="article_body" name="article[body]"> </textarea>
  </div>
  <div class="actions">
    <input name="commit" type="submit" value="Create Article" />
  </div>
</form>
As you can see very similar HTML. Formtastic has a few extras to give you greater flexibility.

How does it look?

Formtastic Form

Rails Form

As you can see, the Formtastic form aligns the elements to make for a smoother look.

NOTE: Formtastic forms will grow/shrink to fill the whole width of the screen. Generally you will want to put the form in a div with a fixed width.

Hints and Errors

Hints

Adding a hint to your inputs is as simple as adding a hint value to the input

  <%= f.inputs do %>
    <%= f.input :title, hint: 'Make it a good one' %>
    <%= f.input :body %>
  <% end %>

Here is how the hint looks

Labels

You can easily change the label for an input, as human friendly names don't always match up to table column names.

  <%= f.inputs do %>
    <%= f.input :title, label: 'Article Title', hint: 'Make it a good one' %>
    <%= f.input :body %>
  <% end %>

Here is how the custom label looks

Errors

If a field is required, Formtastic will automatcially add an * next to the name and will display an error below the input field if it is blank.

class Article < ActiveRecord::Base
  validates_presence_of :title
end

Formtastic will automatically display errors next to the input.

NOTE: Formtastic will ONLY do this for all error messages that relate to the input fields in the form. If you have a generic message or message that applies to an input field that isn't displayed in the form, then you need to add in code to handle that message. The error reporting code in the standard Rails scaffold will work.

Custom HTML attributes

You can customize all your input fields HTML attributes using the input_html hash option.

<%= f.input :title, label: 'Article Title', hint: 'Make it short', input_html: { size: 10 } %>
<%= f.input :body, input_html: { rows: 10, cols: 25 } %>

What about Relationships?

Formtastic automatically handles relationships between models for you.

# generate the Article scaffold with a category
rails generate scaffold Article title:string category:references body:text author:string

# if you already have the Article model, here is the migration
rails generate migration AddCategoryToArticle category:references author:string
# add the relationship to the Article model
belongs_to :category

# update strong parameters in the Article Controller
def article_params
  params.require(:article).permit(:title, :body, :category_id, :author)
end

# generate the Category model, we are adding in a cat_type for further classification
rails generate model Category name:string cat_type:integer
# create categories in the Rails console
Category.create(name: 'Technology', cat_type: 1)
Category.create(name: 'Lifestyle', cat_type: 2)
Category.create(name: 'Business', cat_type: 1)
Category.create(name: 'Entertainment', cat_type: 2)

Formtastic will automatically reference the relationship if you reference it by the relationship name category and not by the table column name category_id

<%= f.inputs do %>
  <%= f.input :title %>
  <%= f.input :category %>
  <%= f.input :body %>
<% end %>

Here is how it will look

Further Select Tweaks

Once again you can customize this further with a few options.

Remove the blank entry

<%= f.input :category, include_blank: false %>

Use a custom drop down list

<%= f.input :category, collection: Category.where(cat_type: 1) %>

Merged all into one

<%= f.input :category, collection: Category.where(cat_type: 1), include_blank: false %>

What about fully custom selects in a string field?

You can specify any field to use a select box and use a Model collection or a custom hash/array for the data.

<%= f.input :author, as: :select, collection: ['Pam','Steve', 'Dave', 'Meg'] %>

NOTE: You can combine all the Formtastic options together to get your input fields just the way you want them.

See the Formtastic site for extensive examples of all the possibilities.

One last one: Checkboxes

So to round out our checklist, lets add a checkbox! For this example, lets add tags

# generate the Tag and Tagging models
rails generate model Tag name:string
rails generate model Tagging article:references tag:references

# Add the tag relationship to the Article model
class Article < ActiveRecord::Base
  has_many :taggings
  has_many :tags, through: :taggings # notice the use of the plural model name
end

# update strong parameters in the Article Controller
def article_params
  params.require(:article).permit(:title, :body, :category_id, :author, { :tag_ids => [] })
end

# create tags
Tag.create(name: 'Fun')
Tag.create(name: 'Scary')
Tag.create(name: 'Sad')
Tag.create(name: 'Excited')

Now the Formtastic Form Code

<%= f.inputs do %>
  <%= f.input :title, label: 'Article Title', hint: 'Make it a good one', input_html: { size: 10 } %>
  <%= f.input :category %>
  <%= f.input :body, input_html: { rows: 10, cols: 25 } %>
  <%= f.input :tags, as: :check_boxes %>
  <%= f.input :author, as: :select, collection: ['Pam','Steve', 'Dave', 'Meg'] %>
<% end %>
As you can see, its as simple as specifying the tags relationship should be displayed as check boxes. Formtastic understands the has_many :tags, through: :taggings relationship and automatically handles things for you.

Lots of Formtastic Inputs

Formtastic will choose an input based on the column type, though you can manually specify the type as show above. Here is a short list taken from the Formtastic site:

  • :select – a select menu. Default for ActiveRecord associations: belongs_to, has_many, and has_and_belongs_to_many.
  • :check_boxes – a set of check_box inputs. Alternative to :select for ActiveRecord-associations: has_many, and has_and_belongs_to_many.
  • :radio – a set of radio inputs. Alternative to :select for ActiveRecord-associations: belongs_to.
  • :password – a password input. Default for column types: :string with name matching "password".
  • :text – a textarea. Default for column types: :text.
  • :date_select – a date select. Default for column types: :date.
  • :datetime_select – a date and time select. Default for column types: :datetime and :timestamp.
  • :time_select – a time select. Default for column types: :time.
  • :boolean – a checkbox. Default for column types: :boolean.
  • :string – a text field. Default for column types: :string.
  • :number – a text field (just like string). Default for column types: :integer, :float, and :decimal.
  • :file – a file field. Default for file-attachment attributes

Formtastic can handle just about everything you throw at it, even nested forms. Be sure to check the Formtastic site

What next?

Install Formtastic and see how much it speeds up your form development.

Make sure you visit the The official Formtastic site and view the readme to see what is there.

Don't forget, you can use your own custom CSS to completely control the look and feel of your form. Formtastic generates great HTML for you to hook into.

Resources

The official Formtastic site - Required reading, one of the best readme documents out there.

Formtastic Wiki - Even more details and guides for Formtastic.

comments powered by Disqus