Form helpers are designed to make working with resources much easier compared to using vanilla HTML.
Typically, a form designed to create or update a resource reflects the
identity of the resource in several ways: (i) the url that the form is sent
to (the form element's action
attribute) should result in
a request being routed to the appropriate controller action (with the
appropriate :id
parameter in the case of an existing
resource), (ii) input fields should be named in such a way that in the
controller their values appear in the appropriate places within the
params
hash, and (iii) for an existing record, when the form
is initially displayed, input fields corresponding to attributes of the
resource should show the current values of those attributes.
In Rails, this is usually achieved by creating the form using
form_for
and a number of related helper methods.
form_for
generates an appropriate form
tag and
yields a form builder object that knows the model the form is about. Input
fields are created by calling methods defined on the form builder, which
means they are able to generate the appropriate names and default values
corresponding to the model attributes, as well as convenient IDs, etc.
Conventions in the generated field names allow controllers to receive form
data nicely structured in params
with no effort on your side.
For example, to create a new person you typically set up a new instance of
Person
in the PeopleController#new
action,
@person
, and in the view template pass that object to
form_for
:
<%= form_for @person do |f| %> <%= f.label :first_name %>: <%= f.text_field :first_name %><br /> <%= f.label :last_name %>: <%= f.text_field :last_name %><br /> <%= f.submit %> <% end %>
The HTML generated for this would be (modulus formatting):
<form action="/people" class="new_person" id="new_person" method="post"> <div style="display:none"> <input name="authenticity_token" type="hidden" value="NrOp5bsjoLRuK8IW5+dQEYjKGUJDe7TQoZVvq95Wteg=" /> </div> <label for="person_first_name">First name</label>: <input id="person_first_name" name="person[first_name]" type="text" /><br /> <label for="person_last_name">Last name</label>: <input id="person_last_name" name="person[last_name]" type="text" /><br /> <input name="commit" type="submit" value="Create Person" /> </form>
As you see, the HTML reflects knowledge about the resource in several spots, like the path the form should be submitted to, or the names of the input fields.
In particular, thanks to the conventions followed in the generated field
names, the controller gets a nested hash params[:person]
with
the person attributes set in the form. That hash is ready to be passed to
Person.create
:
if @person = Person.create(params[:person]) # success else # error handling end
Interestingly, the exact same view code in the previous example can be used
to edit a person. If @person
is an existing record with name
“John Smith” and ID 256, the code above as is would yield instead:
<form action="/people/256" class="edit_person" id="edit_person_256" method="post"> <div style="display:none"> <input name="_method" type="hidden" value="patch" /> <input name="authenticity_token" type="hidden" value="NrOp5bsjoLRuK8IW5+dQEYjKGUJDe7TQoZVvq95Wteg=" /> </div> <label for="person_first_name">First name</label>: <input id="person_first_name" name="person[first_name]" type="text" value="John" /><br /> <label for="person_last_name">Last name</label>: <input id="person_last_name" name="person[last_name]" type="text" value="Smith" /><br /> <input name="commit" type="submit" value="Update Person" /> </form>
Note that the endpoint, default values, and submit button label are
tailored for @person
. That works that way because the involved
helpers know whether the resource is a new record or not, and generate HTML accordingly.
The controller would receive the form data again in
params[:person]
, ready to be passed to
Person#update
:
if @person.update(params[:person]) # success else # error handling end
That's how you typically work with resources.