Formtastic 2 Preview: Custom Inputs

Published 7 April 11 by Justin French

I’ve been pouring more hours than I care to admit into a massive refactor of Formtastic. I’m really happy with where it’s headed, so it’s time to share some of the goodies!

Custom inputs (the ability to define your own input type) has been on my list since day one, and the refactor has made it really easy. Each input is now handled by it’s own class, which obviously lets us take advantage of things like class inheritance and composition with modules.

Under the hood, when you render an input with something like this:

  <%= f.input :title, :as => :number %>

We’re creating a new instance of the Formtastic::Inputs::NumberInput class and calling #to_html on it. That class looks something like this:

  class NumberInput 
    include Base
    include Base::Stringish
    def to_html
      input_wrapping do
        label_html <<
        builder.number_field(method, input_html_options)
      end
    end
    def input_html_options
      {
        :min => validation_min,
        :max => validation_max,
        :step => validation_integer_only? ? 1 : nil 
      }.merge(super)
    end
  end

Most of the heavy lifting is done in the included modules. This class is only concerned with the things that are different about a number input compared to other “stringish” inputs like SearchInput, PhoneInput, EmailInput and of course StringInput.

In this case, we’ve added default min, max and step attributes for the <input> tag, and implemented #to_html, which calls Rails’ number_field helper. It could (and probably will) be abstracted even further before I’m done, but for now it’s all about the vibe of the thing.

Here’s the cool bit. Before instantiating Formtastic::Inputs::NumberInput, we try to instantiate a top-level class NumberInput. This means you can create a NumberInput class in app/inputs/number_input.rb, inherit from Formtastic::Inputs::NumberInput and make any modifications you want to the class. Under the hood, there’s about 55 methods available on NumberInput which you can override, but you could ultimately do anything you want by overriding #to_html:

  class NumberInput < Formtastic::Inputs::NumberInput
    def to_html
      "Return whatever HTML string you want, however you want."
    end
  end

A more likely and less dramatic scenario might be to add a special class to the <li> wrapper tag, ditch those new HTML5 min, max & @step attributes and use a text input instead of the HTML5 number input. Easy:

  class NumberInput < Formtastic::Inputs::NumberInput
    def to_html
      input_wrapping do
        label_html <<
        builder.text_field(method, input_html_options)
      end
    end
    def input_html_options
      super.reject { |k, v| [:min, :max, :step].include?(k) }
    end
    def wrapper_html_options
      super.merge(:class => "#{super[:class]} special-class" )
    end
  end

Thank you, Ruby!

Maybe you want to alter EmailInput so that it always includes some fluffy hint text about privacy, and maybe some placeholder text. In other words, you want to define what your app needs from an email input, so that you don’t have to repeat yourself all over the app. Easy:

  class EmailInput < Formtastic::Inputs::EmailInput
    def hint_text
      "Trust us, we never send spam and never share your email address with others."
    end
    def placeholder_text
      "you@yours.com"
    end
  end

Here’s the awesome bit. You can create your own custom inputs in the same way. Here’s a few ideas:

  • subclass NumberInput to create an AgeInput
  • subclass StringInput to create a jQuery DatepickerInput
  • redefine DateTimeInput to be way less complicated than it is right now (perhaps as a HTML5 date picker with Javascript fallback?)

This stuff is in the master branch on Github right now. If you’ve got a little app in development, now would be a great time to take it for a spin and give me some feedback — simply bundle Formtastic from the master branch directly with the :git option, have a play, then switch back to the gem.

Perhaps now is a great time to shamelessly plug the Pledgie campaign? I’m doing this for myself, but it’d be great to know I’m also doing it for you, your boss or your clients as well.

Options

What is this?

portrait of Justin

This is the online home of Justin French, a designer & web application developer located in Melbourne, Australia. I like finding ways to make things work better. I like clarifying and simplifying. I like to understand how you understand things.

» read more

Subscribe to my feed

Follow me on Twitter

@justinfrench

More Notebook Articles

Show more notebook articles

Search