homeASCIIcasts

234: Simple Form 

(view original Railscast)

Other translations: Pt Es It

A few months ago a couple of episodes covered the Formtastic gem [watch, read]. This offers a convenient way to generate the view code for forms in Rails. In this episode we’ll take a look at an alternative gem called SimpleForm. Like Formtastic SimpleForm provides a simpler way to generate view code compared to standard Rails view code. If you know Formtastic then SimpleForm’s method calls will seem familiar as they are very similar.

The big question here is given that the gems are so similar why would you choose SimpleForm over Formtastic? One reason is that SimpleForm is more lightweight. It doesn’t include a stylesheet that it expects you to use instead just concentrating on generating HTML markup. It is also more customizable and extendable than Formtastic. If you’ve used Formtastic and feel that it gets in your way a little and forces you to use markup that you’d rather not then it’s well work taking a look at SimpleForm.

Integrating SimpleForm Into an Application

To demonstrate SimpleForm we’ll update a form written using standard Rails view code to use SimpleForm instead. The application is a simple e-commerce application with a number of products, each of which belongs to a category and the form we’ll be modifying is the form for creating a new product. This form has a number of different types of field so will provide a good example to convert to use with SimpleForm.

The New Product form.

To use SimpleForm we must first add the gem to the application’s Gemfile.

/Gemfile

gem "simple_form"

Then, to ensure that it is installed, we need to run

$ bundle install

Now that the gem is installed we need to run a generator that will add a few files that SimpleForm needs into our application.

$ rails g simple_form:install
    create  config/initializers/simple_form.rb
    create  config/locales/simple_form.en.yml
    create  lib/templates/erb/scaffold/_form.html.erb

These generated files are used mainly for customization and we’ll take a look at them shortly. Before we do that we’ll update our product’s form view code which currently looks like this.

/app/view/products/new.html.erb

<%= form_for @product do |f| %>
  <%= f.error_messages %>
  <p>
    <%= f.label :name %>
    <%= f.text_field :name %>
  </p>
  <p>
    <%= f.label :price %>
    <%= f.text_field :price %>
  </p>
  <p>
    <%= f.label :released_on %>
    <%= f.date_select :released_on %>
  </p>
  <p>
    <%= f.label :category_id %>
    <%= f.collection_select :category_id, Category.all, :id, :name %>
  </p>
  <p>
    <%= f.label :rating %>
    <%= f.select :rating, 1..5 %>
  </p>
  <p>
    <%= f.label :discontinued %>
    <%= f.check_box :discontinued %>
  </p>
  <p><%= f.submit %></p>
<% end %>

The two main changes we need to make to the form are to replace form_for with simple_form_for and to replace each pair of labels and inputs with one of SimpleForm’s methods.

/app/view/products/new.html.erb

<%= simple_form_for @product do |f| %>
  <%= f.error_messages %>
  <%= f.input :name %>
  <%= f.input :price %>
  <%= f.input :released_on %>
  <%= f.association :category %>
  <%= f.input :rating %>
  <%= f.input :discontinued %>
  <%= f.button :submit %>
<% end %>

For most of the controls on the form we can use the f.input method. One field where we need to use something different is category. In the original form this field used collection_select to render a drop down menu containing all of the categories.

/app/view/products/new.html.erb

<%= f.collection_select :category_id, Category.all, :id, :name %>

With SimpleForm we can replace this with f.association which will do the same thing.

We can now reload the form and see how it is rendered by SimpleForm.

The form rendered with SimpleForm.

The form looks quite a bit different now as it no longer has the styling that was previously applied to it but it will be easy enough to alter our stylesheet to add some styles that match the class names that SimpleForm uses in its forms.

/public/stylesheets/application.css

.simple_form label {
  float: left;
  width: 100px;
  text-align: right;
  margin: 2px 10px;
}

.simple_form div.input {
  margin-bottom: 10px;
}

.simple_form div.boolean, .simple_form input[type='submit'] {
  margin-left: 120px;
}

.simple_form div.boolean label {
  float: none;
  margin: 0;
}

When you use SimpleForm in your own application’s you’ll want to customize these styles to suit the look of your own application but the CSS above will give you some idea as to what class names are used in the HTML elements that SimpleForm generates. With the styles above in place our form now looks a little better.

The form now has CSS added.

Customizing Fields

For the fields that we have used f.input on SimpleForm has automatically detected each type of column so that “Released on” is rendered as a date column and “Discontinued” is rendered as a checkbox as it represents a boolean column. As an association the “Category” field has been rendered as a drop down menu with a blank option. If we want to customize these fields then we can do so by adding some options. For example we can remove the blank option from “Category” by adding an :include_blank option.

/app/view/products/new.html.erb

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

The original form had a drop down list for the rating field, but this has now been replaced by a text field. We can restore this back to a drop down by using the :collection option and passing it a range.

/app/view/products/new.html.erb

<%= f.input :rating, :collection => 1..5 %>

If we want the list rendered as radio buttons instead we can use the :as option.

/app/view/products/new.html.erb

<%= f.input :rating, :collection => 1..5, :as => :radio %>

When we reload the form now we’ll see that the blank option has gone from the drop down and that the rating fields are rendered as radio buttons.

The rating field is now rendered as a series of radio buttons.

Another great feature of SimpleForm is automatic detection of required fields. We can demonstrate this by making the name and price fields in the Product model required.

/app/models/product.rb

class Product < ActiveRecord::Base
  attr_accessible :name, :price, :released_on, :category_id, 
  :rating, :discontinued
  belongs_to :category  
  validates_presence_of :name, :price
end

That’s all we need to do. when we reload the form we’ll see those fields marked with asterisks and if we try to submit it without filling in those fields we’ll see the error messages for those fields displayed.

The form showing the required field errors.

We can also easily add a hint message to each field. Let’s say that we want to give a hint that prices should be entered in UK pounds. We just need to add a :hint option to the field.

/apps/views/products/_form.html.erb

<%= f.input :price, :hint => "prices should be in UKP." %>

This will add the hint after the form field.

The Price field now has a hint.

There is more information on the options that can be passed to these fields in the README documentation for SimpleForm. It’s worth looking at the documentation for Formtastic too as many of the options that it uses can be used by SimpleForm too.

Customizing SimpleForm

When we ran the SimpleForm generator earlier it created three files.

$ rails g simple_form:install
    create  config/initializers/simple_form.rb
    create  config/locales/simple_form.en.yml
    create  lib/templates/erb/scaffold/_form.html.erb

If we want to customize SimpleForm across an entire application then we can do so by modifying one or more of these files. The first file contains a number of commented-out configuration options and there are a lot of configuration changes we can make here. For example we can alter the order that each fields components are rendered; we can change that tag that wraps each form field and we can change the default size of the text field. We want narrower text fields in our application so we’ll change the default value of 50 to 30.

/config/initializers/simple_form.rb

# Use this setup block to configure all options available in SimpleForm.
SimpleForm.setup do |config|

  # Other options removed...

  # Default size for text inputs.
  config.default_input_size = 30
end

The next file that is generated is the locales file and this is where we can internationalize the form.

/config/locales/simple_form.en.yml

en:
  simple_form:
    "yes": 'Yes'
    "no": 'No'
    required:
      text: 'required'
      mark: '*'
      # You can uncomment the line below if you need to overwrite the whole required html.
      # When using html, text and mark won't be used.
      # html: '*'
    error_notification:
      default_message: "Some errors were found, please take a look:"
    # Labels and hints examples
    # labels:
    #   password: 'Password'
    #   user:
    #     new:
    #       email: 'E-mail para efetuar o sign in.'
    #     edit:
    #       email: 'E-mail.'
    # hints:
    #   username: 'User name to sign in.'
    #   password: 'No special characters, please.'

Even if your application doesn’t need to display multiple languages this file is still a useful place to alter some of SimpleForm’s options such as the text that is displayed against required fields.

The final file that is generated overrides the form partial for the scaffold generator.

/lib/templates/erb/scaffold/_form.html.erb

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

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

  <div class="inputs">
  <%- attributes.each do |attribute| -%>
    <%%= f.<%= attribute.reference? ? :association : :input %> :<%= attribute.name %> %>
  <%- end -%>
  </div>

  <div class="actions">
    <%%= f.button :submit %>
  </div>
<%% end %>

In Rails 3 we can override any template file in a generator by adding it to our application so if we want to customize the way a generator works to fit the way we work we can just create a new template file.

That’s it for this episode. SimpleForm makes it easy to create forms in your Rails applications and is well worth taking a look at.