Travis Emmett's blog

A coder in training's thoughts

What's a Form_for, or for That Matter, a Form_tag? Some Examples...

Last week I was introduced to the magic that are the various form builder methods in Rails. It was a little intimidating to me because I am sort of a control freak with my code and Rails makes a number of assumptions behind the scenes as to what you are trying to do. But it's also amazing because with that automation, you can say goodbye to writing out html forms manually and these methods can be very smart. There is a ton of documentation online which is a great resource, but I was a little frustrated that it was hard to find an example all in one spot of a form's ruby code, the html output, what the form looked like on a web page, and the corresponding params hash sent on submission of the form.

So, in case you are looking for a quick reference to these tags, here are a few briefly explained:

form_tag

The form_tag is an ActionView helper method that follows the url provided to it and defaults to the POST method unless you specify otherwise. Here we are specifying a PATCH action in order to update a record:

views/concretes/edit.html.erb:

1
2
3
4
5
<%= form_tag("/concretes/#{@concrete.id}", :method => 'patch') do %>
<%= label_tag ("mix type") %>
<%= text_field_tag('concrete[mix_type]', @concrete.mix_type) %>
<%= submit_tag "Update Concrete" %>
<% end %>

The second argument in text_field_tag is responsible for pre filling in the value of the existing record (which you’ll notice is filled in below) in order to submit an update.

Outputted HTML:

1
2
3
4
5
6
7
<form action="/concretes/1" accept-charset="UTF-8" method="post">
<input name="utf8" type="hidden" value="✓"><input type="hidden"
name="_method" value="patch"><input type="hidden" name="authenticity_token" value="aBUUH4T65nmHGLS/uATo5yNttcsWRW8gpyrV4MvPEDbfOKWuqmC498fV8r9WAYHBBvHQOBNctaeeLqcuk27iRQ==">
<label for="mix_type">Mix type</label>
<input type="text" name="concrete[mix_type]" id="concrete_mix_type" value="stone" >
<input type="submit" name="commit" value="Update Concrete">
</form>

Example form (non functioning):

Params content:

And here is the content of the params hash after submission of the form:

1
2
3
4
5
6
7
8
9
10
{"utf8"=>"✓",
 "_method"=>"patch",
 "authenticity_token"=>
  "aBUUH4T65nmHGLS/uATo5yNttcsWRW8gpyrV4MvPEDbfOKWuqmC498fV8r9WAYHBBvHQOBNctaeeLqcuk27iRQ==",
 "concrete"=>
  {"mix_type"=>"stone"},
 "commit"=>"Update Concrete",
 "controller"=>"concretes",
 "action"=>"update",
 "id"=>"1"}

This params hash could then be intercepted in the concretes controller's update method where you would save the changes to the existing record.

form_for

The form_for method is another ActionView helper that offers an additional level of abstraction (and ease) over it's lower level form_tag counterpart. This is a good approach to take if you are practicing the Rails convention of RESTful routing and you are using a standard active record object, in this case an instance of the Baby class. Because Rails makes so many assumptions about your form, it is good practice to still double check your data is being routed correctly. Below is a basic illustration of entering a new baby name in a database:

views/babies/new.html.erb:

1
2
3
4
5
6
7
8
9
<%= form_for (@baby) do |f| %>
<%= f.label :first_name %>
<%= f.text_field :first_name %>

<%= f.label :birth_date %>
<%= f.date_field :birth_date %>

<%= f.submit %>
<% end %>

Note the amazing number of assumptions Rails has made about your form! Based on the view type that the form_for is added to (in this case our new Baby view), Rails guesses correctly the method (post), the name of the submit button (Create Baby), the desired nesting of data in the params hash for mass assignment ease -- baby[first_name] and baby[birth_date], among other things.

Outputted HTML:

1
2
3
4
5
6
7
8
9
10
<form class="new_baby" id="new_baby" action="/babies" accept-charset="UTF-8" method="post"
_lpchecked="1"><input name="utf8" type="hidden" value="✓"><input type="hidden"
name="authenticity_token" value="6/3miTvGAxS4pv3D2/
zQU8iLYnwDB1wDaYC6e7qDknNc0Fc4FVxdmvhru8M1+bl17RcHjwYehoRQhMi14iJgAA==">
<label for="baby_first_name">First name</label>
<input type="text" name="baby[first_name]" id="baby_first_name" >
<label for="baby_birth_date">Birth date</label>
<input type="date" name="baby[birth_date]" id="baby_birth_date">
<input type="submit" name="commit" value="Create Baby">
</form>

Example form (non functioning):

Params content:

{"utf8"=>"✓",
 "authenticity_token"=>
  "6/3miTvGAxS4pv3D2/zQU8iLYnwDB1wDaYC6e7qDknNc0Fc4FVxdmvhru8M1+bl17RcHjwYehoRQhMi14iJgAA==",
 "baby"=>
  {"first_name"=>"Brandnew",
   "birth_date"=>"2015-07-13"},
 "commit"=>"Create Baby",
 "controller"=>"babies",
 "action"=>"create"}

This params hash could then be intercepted in the babies controller's create method where you would add the data from the params hash to the database.