Rails Form Helpers

Blaire Grant
10 min readMay 9, 2021

For Flatiron School’s Phase 3 Software Engineering project, students are required to build a Ruby on Rails application that manages related data through complex forms and RESTful routes. The goal of this project is to build a content management system. In order to successfully complete this project, students need to have a thorough understanding of MVC architecture, Active Record associations, Rails routing, and Rails forms.

I am a huge Disney fan and was determined to incorporate that theme into one of my projects as a Flatiron student, and I chose to do so with this application. I created a Disney Movie Watchlist App where users can either browse through a list of Disney movies or they can choose to search for any other movie they would like. Once they select the movie they would like to see more information about, that movie’s data will be displayed to them. Next, they can decide if they would like to add that movie to a watchlist that they create, or they can simply search for another movie. They also have the option to create a review for the movie, whether they add it to one of their watchlists or not. So, as you can imagine, there are many forms involved in my application.

After getting through the initial steps of successfully populating the database with Disney movies, I was ready to start building out the rest of my application. I had to get really comfortable with using Rails forms as I used them in almost every view in my application. I think a very important point to make here, is to not only understand how to use Rails forms, but to also pay very close attention to your params hash that the form produces. Once you create a form and set up an action in your controller that the form will submit to, carefully check your params to make sure the information you expect to receive is what is actually showing up in your params hash. I used the byebug gem a lot to accomplish this task and get the actions in my controllers, as well as my forms, to perform as I wanted them to.

I thought it would be helpful to go through the different forms that are available to you through Rails to help you get a better understanding of their similarities and differences so that you can choose which will work best for you when starting this project yourself. First and foremost, forms are a way for the user to submit data which can then be used for a search query, to create a record in the database, update a record in the database, or really anything that requires input from the user of the application. There are three main ways of creating forms in Rails. There is the form_tag helper, the form_for helper, and the form_with helper. The form_tag differs from the form_for in its simplicity, and is therefore typically used for different things, so it is important to know the difference between them when creating your application.

Form_tag

We will start with the form_tag helper. This is the most basic form helper which makes it great to use for simple things like a search query. This is because it is not associated directly with a model object. The form_tag helper uses form elements, rather than a form builder, to build out a form. In order to add fields to the form_tag block, you would have to add form element tags like the text_field tag, label_tag, and submit_tag. However, you can also use form controls such as the check_box_tag or radio_button_tag to allow your user to choose from a set of options. There are various helpers that can be used in a form_tag, so keep in mind, that just because it is basic, does not mean that you don’t have many options available to you in order to create a form that would be really useful. Some of the downsides to this particular form helper are that the form must be manually passed to the route where the form parameters will be submitted so you have to specify where to send the data. Also, this form is not already associated with a model object, so when you create the form, you need to include the model object’s name followed by the attribute in both the label_tag and form element tag helpers as seen below.

Here is an example of the basic form_tag helper:

As stated before, be sure to pay special attention to the params hash the gets submitted to the specified action in your controller. Here are the parameters that this form produced:

There are a few things you may notice in the params hash above. One is the authenticity token. This may be unfamiliar to you right now, but it is a part of every form in Rails, other than get request forms. It is a Rails security feature for Cross-Site Request Forgery Protection and is automatically generated by form helpers to prevent CSRF attacks. If you would like to read more about CSRF, click here. Another thing you may notice about the params hash is “permitted:false”. The controller will not allow certain fields if they have not been whitelisted in the strong params for that controller. So remember, if your form is related to an object, you will need to permit any fields in your controller’s strong params that are needed in order to either create or update your object. You will also notice that each attribute is listed after its associated object. This is because we set it up this way in our form by nesting the attribute after the model object’s name. We purposely nested it this way in order for it to correlate with our strong params. For example, params[“movie”][“Title”] will return “Beauty and the Beast”. This is why, in this case, the strong params for the movie controller would need to look like this:

To read more about the form_tag and see other helpers available for generating form elements, click here.

Form_for

Next, there is the form_for helper which is a Ruby method. This is a more advanced form helper and deals directly with model objects. Therefore, it is great when creating or updating model objects without having to specify the model object’s name followed by the attribute as you would have to do when using the form_tag helper. Form_for binds the form to an Active Record model object because you pass it an instance of the model as an argument. It uses a block that yields a FormBuilder object to generate the form elements specified in the form which correspond to the model’s attributes. Form_for will also try to route the form to the appropriate action in the associated controller because it follows RESTful conventions. It can determine this based on whether the instance of the model you pass to the form is a new model object or an already created model object that already exists in your database. Form_for is great because it is already bound to an object and less verbose than the form_tag. However, either one can be used to accomplish the same thing.

Here is an example of the form_for helper:

Here are the parameters that this form produced:

You will notice in the params hash above that the authenticity token is still automatically produced by the form. Remember, that is because this is not a get request as we are creating a movie here. Permitted also evaluates to true in our params hash this time because we set up our strong params to accept all of the movie attributes needed to either create or update this object. Also, even though we used form_for this time rather than form_tag, the params hash still looks the same. That is because we set each form up to produce the same result.

To read more about the form_for method and to see more examples, click here.

Form_with

Finally, there is the form_with helper which is also a Ruby method. This form helper is basically a combination of both the form_tag and form_for helpers in that you can generate a form with or without associating it to a model object. Therefore, the features of form_tag and form_for both apply to this method as well so it can be used in several different ways. By using the model argument in the form_with helper, you will automatically bind the FormBuilder object to the model object. In this case, you would pass it an instance of the model, as in, model: @movie. However, you also have the option to pass in the URL path instead, if not using, or specifying the model object when using one. In this case, you would just pass in the URL endpoint, as in, url: movie_path. Another feature form_with has is that you can set the scope if generating a form for a resource that does not have an associated model, as in, scope: session. As you can imagine, form_with is the preferred form helper because it is the most versatile and you will only need to remember the syntax for one form helper rather than two. However, with that being said, form_with does allow you to mix the form helpers from both form_tag and form_for without causing any errors. Form_with, is therefore, very flexible as well.

Here is an example of the form_with helper using the model argument which automatically infers both the URL and the scope:

Here are the parameters that this form produced:

As you can see, just like the other two examples above, the params hash here looks exactly the same. Each of the model’s attributes is nested in the params hash under the model object, in this case, movie. As stated before, always check your params hash to make sure it looks the way you expect it to. The way the params comes in is very important because it correlates to your controller’s strong params. Therefore, each attribute that comes through on your form will need to be permitted in your strong params in order to either create or update your object successfully. When testing this out in your controller, add byebug to the very top of the controller’s action that you are inspecting. After submitting your form, you should hit the correct controller action. If not, you may need to double check your routes or your form to see why it isn’t sending it to the correct action in your controller. Once you hit the correct controller’s action, check your console to see if you are in your byebug. From there, you can check your params hash that your form produced. Check to see if permitted is set to true or false. If set to true, then your form should be performing as expected. If set to false, then you can check your model object to see what the errors are. For example, in the form above, we used model: @movie. If you enter @movie.valid? in your byebug, it will return either true or false. If false, you can then enter @movie.errors and it will show you the errors that are preventing this model object from either being saved or updated. You can check whether the error is an unpermitted attribute in your strong params or a validation error. This is useful because if you were to add a hidden field to your form to associate this object to another object, for example, to associate a movie object to a genre object, you may need to also whitelist your :genre_id in your strong params. I found using byebug and following these steps to be very helpful when debugging.

To read more about the form_with method and to see more examples, click here.

To read more about strong parameters, click here.

Now that you have learned about the different forms available for use in a Rails application, it is important to note, that both the form_tag and form_for helpers are soft-deprecated. That’s not to say that you can’t use them for now. However, if you are not yet comfortable using a specific form helper, then I would highly recommend getting used to using form_with, not only because of its flexibility and versatility, but also because it is the new standard. Even if you are comfortable using another form helper, I think after you start using the form_with method, you will soon realize that it is not that different from what you are already used to, so definitely worth giving a try.

I hope you found this overview of Rails forms helpful. Please check out my project and let me know what you think…

https://github.com/grantba/disney_movie_watchlist_app.git

--

--