Skip to content

Upgrading to Simple Form 2.0

dansperfect edited this page Aug 24, 2016 · 3 revisions

Upgrading to SimpleForm 2.0

If you are seeing this page, it is likely that you are updating a Rails application to SimpleForm 2.0. But don't fear, upgrading takes just a couple minutes. In this page, we will detail the three areas you will need to change in order to be SimpleForm 2.0 ready.

Make sure to checkout the CHANGELOG for more info on new available configs and other deprecations and bug fixes.

1) Translations

SimpleForm 2.0 fixed a long standing issue of default translations. For example, in previous versions if you wanted to provide a default hint or label for title, you could do:

en:
  simple_form:
    labels:
      age: Idade

This caused conflicts in some cases and was changed in SimpleForm 2.0:

en:
  simple_form:
    labels:
      defaults:
        age: Idade

Fixing this in your locale files is very easy, just check if you have an attribute name directly under a simple_form.labels, simple_form.hints and simple_form.placeholders and move them under the defaults key.

2) Default form class

Also, now SimpleForm generate the CSS form classes as Rails does, adding the action prefix to the object name. You have to update your CSS styles to fit the new form classes. For example:

<%= simple_form_for(@user) do |f| %>
<% end %>

Given @user is not yet persisted, it will generate:

<form class="simple_form new_user">
</form>

Instead of:

<form class="simple_form user">
</form>

A persisted @user object would add the edit_user class instead, the same way Rails does.

3) The new wrappers API

SimpleForm 2.0 ships with a new wrappers syntax which is more flexible and powerful. The new syntax looks like this:

    config.wrappers :tag => :div, :class => :input,
                    :error_class => :field_with_errors do |b|
      # Extensions
      b.use :html5
      b.optional :pattern
      b.use :maxlength
      b.use :placeholder
      b.use :readonly

      # Inputs
      b.use :label_input
      b.use :hint,  :wrap_with => { :tag => :span, :class => :hint }
      b.use :error, :wrap_with => { :tag => :span, :class => :error }
    end

All the options given to config.wrappers above are used to create a div that will wrap all the components in the block.

Imagine your application using SimpleForm 1.x has the following configuration:

    SimpleForm.setup do |config|
      config.components = [ :placeholder, :hint, :label_input, :error ]
      config.wrapper_tag = :p
      config.wrapper_error_class = :fieldWithErrors
      config.hint_class  = :inputHint
      config.error_class = :inputError
    end

It should be rewritten using the new syntax as follows (notice how the configuration values become options in the new syntax):

    config.wrappers :tag => :p, :class => :input,
                     :error_class => :fieldWithErrors do |b|
      b.use :placeholder
      b.use :hint,  :wrap_with => { :tag => :span, :class => :inputHint }
      b.use :label_input
      b.use :error, :wrap_with => { :tag => :span, :class => :inputError }
    end

If you were using :pattern, :maxlength, :placeholder or :html5 features, you should explicitly turn them on:

    config.wrappers :tag => :p, :class => :input,
                     :error_class => :fieldWithErrors do |b|
      b.use :html5
      b.use :maxlength
      b.use :placeholder
      b.use :readonly
      b.use :pattern

      b.use :label_input
      b.use :hint,  :wrap_with => { :tag => :span, :class => :inputHint }
      b.use :error, :wrap_with => { :tag => :span, :class => :inputError }
    end

You should also remove the following methods from your configuration file: wrapper_tag=, wrapper_class=, wrapper_error_class=, error_tag=, error_class=, hint_tag=, hint_class=, components= and html5=. All those methods are deprecated now as they are built-in in the wrappers DSL.

Extra tricks

The information above is all you need to upgrade to 2.0. However, if you want to learn some extra tricks, you can continue reading.

Custom wrappers

The new syntax also allows custom wrappers:

    config.wrappers do |b|
      b.use :placeholder
      b.use :label_input
      b.wrapper :tag => :div, :class => "separator" do |ba|
        ba.use :hint,  :wrap_with => { :tag => :span, :class => :hint }
        ba.use :error, :wrap_with => { :tag => :span, :class => :error }
      end
    end

You may optionally give a name to the custom wrappers:

    config.wrappers do |b|
      b.use :placeholder
      b.use :label_input
      b.wrapper :my_wrapper, :tag => :div, :class => "separator" do |ba|
        ba.use :hint,  :wrap_with => { :tag => :span, :class => :hint }
        ba.use :error, :wrap_with => { :tag => :span, :class => :error }
      end
    end

Given a name to a custom wrapper means that they can be customized on demand:

    # Completely turns off the custom wrapper
    f.input :name, :my_wrapper => false

    # Configure the html
    f.input :name, :my_wrapper_html => { :id => "special_id" }

    # Configure the tag
    f.input :name, :my_wrapper_tag => :p

Per form wrapper

The new wrappers API also allows you define more than one wrapper and pick one to render a specific form. For instance, we could define two wrappers as follow:

    # This is going to be the default
    config.wrappers do |b|
      b.use :placeholder
      b.use :label_input
      b.wrapper :tag => :div, :class => "separator" do |ba|
        ba.use :hint,  :wrap_with => { :tag => :span, :class => :hint }
        ba.use :error, :wrap_with => { :tag => :span, :class => :error }
      end
    end

    # Let's define one without hint or errors
    config.wrappers :small do |b|
      b.use :placeholder
      b.use :label_input
    end

Now, when invoking simple_form_for, we can pick which one to use:

    simple_form_for @user, :wrapper => :small do |f|
      f.input :name
    end

A wrapper can also be given to the input call:

    simple_form_for @user do |f|
      f.input :name, :wrapper => :small
    end

Optional elements

SimpleForm also allows you to use optional elements. For instance, let's suppose you want to use hints or placeholders, but you don't want them to be generated automatically. You can setup them as optional like this:

    # This is going to be the default
    config.wrappers do |b|
      b.optional :placeholder
      b.use :label_input
      b.wrapper :tag => :div, :class => "separator" do |ba|
        ba.optional :hint, :wrap_with => { :tag => :span, :class => :hint }
        ba.use :error, :wrap_with => { :tag => :span, :class => :error }
      end
    end

    # It can also be written as (although the :optional method is preferred):
    config.wrappers :placeholder => false, :hint => false do |b|
      b.use :placeholder
      b.use :label_input
      b.wrapper :tag => :div, :class => "separator" do |ba|
        ba.use :hint,  :wrap_with => { :tag => :span, :class => :hint }
        ba.use :error, :wrap_with => { :tag => :span, :class => :error }
      end
    end

By using optional (or setting them to false), a hint will only be generated when :hint => true is explicitly used. The same for placeholder.


###Community Member Addition:

I wanted to provide a very simple example of the how this be setup in your rails view. You would create this code in a partial _form.html and then render it into your views for New Post or Edit Post. This example is showing a blogs post form, that is using ckEditor for the body field. (ckeditor should be installed by Gemfile: gem 'ckeditor') Following the below example will allow for very simple form setup. When adding additional CSS, SCSS do so line by line refreshing he page as you to ensure you changes isn't breaking anything. Specifically trying to create some of these fields side by side (more then 1 form field on the same row) can be quite tricky depending on the field types there length and etc....

<%= simple_form_for  @post, html: { class: 'form-horizontal' }, wrapper: :horizontal_form do |f| %>

  <div class="form-group">
    <%= f.input :title, label: "Title", class: "form-control" %>
  </div>
  
  <div class="form-group">
    <%= f.input :body, label: "Post Body", :as => :ckeditor, class: "form-control" %>
  </div>

  <div class="form-group">
    <%= f.button :submit %>
  </div> 

<% end %>