A Little Form Help From Your Friends
I have a dirty little secret, and I’m not sure if it’s really the best idea to announce it here being the rather public forum that it is, but here goes:
I hate HTML.
You’re probably wondering why that little statement rates up there as a “dirty little secret,” involving, as it does, no dubious fluids, strange positions, or missing articles of clothing. But it is something pretty wrong for a web monkey to admit, it seems. I look around and watch people talk about how they just love XHTML and CSS and making their pages pass the vaunted XHTML Strict litmus test. But not I; nay, I view it as a necessary evil.
<span id="more-3671"></span>
(Although CSS is a far sight better than the alternative, I wouldn’t say I love it. I wouldn’t even say I’m attracted to it in a more-than-platonic way.)
So it follows that one of my favorite parts of Rails–once you get past the happy shiny “full-stack framework,” and the whole “golly gee, I don’t have to write almost any SQL” rigamarole–is helpers. Especially form helpers. Less HTML == happier Amy.
People Helping Helpers Help People
First Rails cut out the repetitive cruft of building applications from the ground up on your own, or fighting with monolithic XML documents. Then it cut out all those pesky repetitive queries you’d otherwise have to write by hand. The only task left to be minimized, other than clients? HTML.
So in come the helpers. They really do help.
There are essentially two major types of helpers:
- Helpers included with Rails
- Helpers you write yourself
Right now we’re only concerned with the former, and a subgroup of the former to be even more exact–today, I’m writing about form helpers. As the name so cleverly implies, form helpers help you make forms. (Of all the HTML I love to hate, forms definitely occupy a very special place in my heart.)
So They Help. Great. What are they?
Helpers are methods (functions) that aren’t explicitly part of a controller class or model class.
In this case, they’re short little functions that spit out properly formed HTML and take into account all the nitty gritty details of form creation such as automatically repopulating when the form submission fails.
Where Do They Go?
Form helpers are to be used in in your application’s views, including layouts and partials. It’s that simple. Most helpers that come with Rails are meant to do something HTMLy, but it’s not actually required that they spit out HTML. You can write helpers to use in controllers, if you so choose.
When you create your own, they go in one of the files in RAILSROOT/app/helpers/
. But that’s another article altogether.
How Do They Work?
The form helpers you’ll really be interested in work with data from your models. You’ll want to use form helpers to link to specific columns—aka methods—for the table you’ve linked to your model. So there’s a form helper that’s right for just about every column in your table that you want to be represented by a form field.
There are also form helpers for non-model data. You may find they’ll come in useful sometime, too.
Why?
The magic of Rails depends on forms being crafted in exactly the way it expects. It can be a pain to do it by hand—it’s just a lot cleaner and more elegant to go ahead and use the wonderful tools that the Rails makers, in their infinite wisdom, saw fit to provide us. And who can argue with faster, easier, and better?
But enough with vague, but effusive, plattitudes. What you really want to know is this:
- Form helpers take the HTML load off your back
- They result in cleaner views
- They handle stuff like creating an invisible field with the opposite value for checkboxes, moving that particular data handling out of the business logic
- They handle fun tricks like auto-filling themselves when an object of their type is available in the view
- When you have validations in your model and are using form helpers, any field that doesn’t pass its validations is automatically surrounded in a div so that you can color it red or what-have-you to warn the user
What’s the Collective Noun for Form Helpers?
Helpings, of course. Form-related helpers come in the following flavors:
- FormHelper. A collection of tags to create standard inputs like checkboxes, textareas, and so on.
- FormOptionsHelper. For selects, including some helpers with pre-defined data like country names.
- FormTagHelper. These are to save time when creating form elements that don’t follow the AR conventions (e.g., they’re not linked to a model), including starting & ending forms and buttons.
Gettin’ Your Feet Wet
You can get the general gist of how these things work: you have the form helper method, and it takes arguments. Typical arguments include the type of object you’re working on, the method inside the object that the form field applies to, and other options for the field like size.
The exact format varies among the kinds of form helpers, and of course somewhat for each individual form helper. In fact, the only constant you can count on is change itself! (OK, not really, but I always wanted to experience an angry mob with torches outside my home.)
Let’s take, for example, the checkbox_helper. If you go to its API docs, you’ll see something like this:
check_box(object, method, options = {}, checked_value = "1", unchecked_value = "0")
The first things it takes are the object
and method
attributes. Remember that these map to the name of the type of object you’re working on (e.g. what’s the model? Book? then you want to feed it book
) and the name of the column in its database table. If you wanted a column on your Book and it would be best represented by a checkbox—say, “I own it or I don’t own it,” in a column named ownership
—then you could do it this way:
check_box('book','ownership')
You could get fancier, and give the checkbox a CSS class, and set the values it should return if it’s checked or not checked:
check_box('book','ownership', "class='book_checkboxes'",'yes','no')
As you can see in the syntax definition, the defaults for checked_value and unchecked_value are 1 and 0, respectively. When you see a method attribute followed by an = sign, then you know that what is on the other side of the equals sign is the default. If you don’t set it, Rails will assume the default.
Using Form Options Helpers
The checkbox helper is a simple example; most of the plain old form helpers/form tag helpers are. But you may find that other helpers are a bit trickier. Take, for example, the group of form option helpers.
Here’s an example of collection_select
, which takes a collection of AR objects and gives you a pop-up select menu (you can also use the HTML setting to turn it into a multi-select box):
<%= collection_select('book', 'rating_id', @ratings, 'id', 'name') %>
This is deconstructed thusly: First you have the object name, the book, which tells you what you’re working on. Then you have the method (or column) name, rating_id
. After that, you have the collection to draw the options from (you’d get that with something like @ratings = Rating.find_all
in your controller), the ratings column to use for the form key, and then the ratings column to use for the form’s apparent value (to the user).
Here’s the syntax for it, found in the API docs:
collection_select(object, method, collection, value_method, text_method, options = {}, html_options = {})
As you can see, it’s a little hectic. But you’ll get the hang of it.
Multiple Models, One Form
Form helpers will even work when you’re using a form to link together multiple models via associations. Just grab the additional collections in the appropriate method in your controller, like thus:
@book = Book.find(@params[:id]) @sections = Section.find_all @authors = Author.find_all
And then you’ll be free to create form helpers for both the tag and author models, like thus:
<%= text_field("book", "title", "size" => 35) %>
<%= collectionselect('book', 'sectionid', @sections, 'id', 'name') %>
<%= collection_select('author', 'id', @authors, 'id', 'firstName') %>
As you can see, since an article has only one section, the collection_select
is called with the book object and the method name for the column section_id
. Whereas there’s a hasandbelongs_to_many relationship between authors and books, so the collection_select
uses the object name and column from the author model.
The Wrap-Up
I never was good at endings. Or goodbyes. So goodbye, gentle reader. I hope I served as a handy flashlight in the dark caverns of the API docs. You should download my form helpers cheat sheet. Enjoy!
And don’t hesitate to stop by the IRC channel, #rubyonrails
on irc.freenode.net
, and say hello. I’m eriberri
and there are lots of helpful people about.
I thout to do it in my local version…
I thout to do it in my local version
Thanks. Updated appropriately
Well at last catched the problem
Thanks
I was very dissapointed of this!
That’s awesome
The content of your show is great, I really enjoy it.