Rails form_for Helpers Under the Hood
If you’ve ever worked with Rails, there’s a good chance you’re already somewhat familiar with the form_for
, which, as the Ruby Docs define it,
This means that if I have a particular class model, say, Student
, I can define an instance variable @student
in my students_controller.rb (either Student.new
or Student.find(params[:id])
if I’m editing an existent one) and pass it to the form in my view:
The form now has knowledge of all of the attributes held by instances of the Student
class, but that knowledge is all it has— it won’t actually display anything at this point. To populate our form with fields, buttons, dropdown menus and whatever else, we need to make use of the FormBuilder (the |f|
shown above) and form helpers. Let’s add three helpers, a label
, a text_field
and a submit
:
We now have a very basic form on the page:
While this doesn’t look like much, its functionality is pretty cool. Because we’re using a form_for
and have tied it to an instance of Student
, when we submit it, it will set the instance’s actual :name
value as whatever we enter. What f.text_field :name
is actually shorthand for in this case is text_field @student, :name
. The FormBuilder (|f|
) is telling the form helper (text_field
) to apply the attribute value that the user enters (:name
) to an instance of a model (@student
).
When the attribute we’re entering data for is something simple, like a name, a text_field
is perfect for the job, but as the data and the way we want the user to enter it get more complex, it won’t necessarily be appropriate. What if we want the user enter a school for a student, but we already have a School
model that Student
belongs to? We could give them a text_field
to fill out, but the odds of them guessing one of the schools in our ActiveRecord database and instantiating a valid student are almost non-existent. We instead need to limit their options to the schools that exist in our database. This is a perfect situation for either a dropdown menu, the helper for which is collection_select
. With the following school instances to choose from
the code we would add to our form would look like this:
The collection we’re selecting from here is @schools
(which is defined in schools_controller.rb as School.all
), the method we’re calling to select each school from the collection is school.id
, :id
is populating the dropdown menu with the instances of school that can be selected and passed as a value to our student instance when the form is submitted, and :name
is providing the string that will be printed in the menu. This is what it would look like on our view page:
We could also use radio buttons to achieve the same purpose. These can be written out individually with the radio_button
form helper as follows:
But there is also a collection_radio_buttons
helper that works the same way as collection_select
that will quickly do our work for us:
These form helpers alone are enough to make a wide variety of perfectly functional forms, but Rails has several more that I won’t go into detail on here. A few that are worth considering are check_box
, time_zone_select
, date_select
. There’s also a useful form helper cheat sheet here if you’d like to see the syntax for each helper:
Keep in mind that you can use a form_for
both to create new instances of a model and to edit existing ones. Because the form_for
is tied to a particular instance, when you use one as an edit form it will actually display the current instance’s values in each of the form fields. While you don’t need this in an edit form, it’s nice for the user to be able to have an immediate reference for the values they’re trying to change.