Rails form_for Helpers Under the Hood

Aaron Smith
4 min readJun 13, 2019

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.

--

--