Refactoring ActionView Form Helpers

Brian Lego
3 min readAug 17, 2020

Since Rails 5.1 theres a new form in town and it goes by the name of ‘form_with’.

The Predecessors: <form_for> & <form_tag>

Those familiar with Ruby on Rails know that the two main Form Helpers that Rails provides out of the box are <form_tag> and <form_for>. Say for example you have an Article model that you would like the user to be able to create another instance of:

The ActionView Helper allows us to set an object for the block |f| and therefore associate attributes to it when created, ie :title. This form helper is a simple way to create a form written in ruby that then outputs to the following HTML which can be read by the browser. Now what if we wanted a form didn’t have a model written that we could then associate the form with? Never fear, <form_tag> is here.

Nearly identical HTML outputs as the <form_for>, <form_tag> however doesn’t need an instance or a model to build off of, it simply needs a url or path and doesn’t yield to a block. You are able to assign attributes, if necessary, nearly the same way as before but instead using input tags.

Now something you may have noticed. The two form helpers end up producing nearly Identical HTML. Rails developers must have obviously realized this was an inefficient way of integrating forms into applications as well as they came up with the alternative <form_with>

Simply put, <form_with> gives you the best of both worlds.

Here it is operating similarly to the <form_for>. Its creating a block built around the article instance. It can be written nearly the exact same with given a local url path. By simply changing line 1 to form_with url: "/articles" you are able to achieve the same HTML.

There are some subtle differences that come with <form_with> as opposed to its sisters <form_for> and <form_tag>. The first being that data-remote as you can see in the example above gets sets by default to true . This means the article will be submitting using AJAX although you can specify and change this if needed and add local: true to line 1.

Another subtle difference is that <form_with> no longer automatically assigns class or id . It allows you as the developer to assign which HTML elements you wish to have classes and ids. <form_with> also allows you to specify scope with using a url. <%=form_with url: '/articles', scope: articles do |f| %> gives you the ability to assign the params when submitting that then point them to the correct controller. Another notable change is when nesting things within your form. Before you would have used the fields_for syntax but with <form_for> you simply use fields.

With the new addition of <form_with> it simplifies writing forms into a single ActionView Helper and allows for the syntax to write forms for both an instance of a model or a url path the same. With this new change the code for <form_for> and <form_tag> will more than likely slowly be deprecated.

To read more about all the ActionView Helpers for forms here are some links:

--

--