Ruby on Rails/ActionView/Forms

From Wikibooks, open books for an open world
Jump to: navigation, search

Forms[edit]

Basic[edit]

Forms are an important part of every web site. We use them to contact the site owners to provide log in credentials or to submit data. Rails has vast support for forms and many build in tags to help you create forms quick and easily.

The most basic form you can get is a simple input field for your name:

<%= form_tag do %>
  <%= label_tag(:my_name, "My name is:") %>
  <%= text_field_tag(:my_name) %>
  <%= submit_tag("Process") %>
<% end %>

This will create a very basic form like

<form action="/products/test/1" method="post">
 <div style="margin:0;padding:0">
 <input name="authenticity_token" type="hidden" value="KBBEVzSZOkCi/s9LKhYvW/gdwyZzwH2n39py5FggaT4=" />
 </div>
 
 <label for="my_name">My name is:</label>
 <input id="my_name" name="my_name" type="text" />
 <input name="commit" type="submit" value="Process" />
</form>

This was achieved by creating a simple action called test.html.erb inside our products view,

def test
  #nothing here yet
end

An empty action inside the controller was added. The page was called inside the browser http://localhost:3000/products/test/1. Because we haven't altered the routes we have to provide an id of a product. Additionaly Rails has created a "authenticity_token" to provide security features to our form. You also notice that there is an id for our input. Rails provides the id for every form element with the names you provided. Of course this can be altered by providing the proper option.

The following list should give you an overview of some form tags. As most of the tags work in a similar manner, it should be easy to figure out how much of them works. Also be sure to take a look at the official API.

Radio Boxes:

To create radioboxes simply use

<%= radio_button_tag :category, "books", true %>

The above will create

<input id="category_books" name="category" type="radio" value="books" />

If you want to change the id you can pass your own id to to tag (:id => "someid"). To preselect an item the 3 option that the helper receives is supposed to be a boolean.

Submit Button:

<%= submit_tag ("Save products", :class => "button") %>

will create a submit button

<input name="commit" type="submit" class="button" value="Save products" />

Text fields:

<%= text_field_tag ('rails') %>

will create an empty text field:

<input id="rails" name="rails" type="text" />

As usual you can add HTML options or specific values

<%= text_field_tag ('price', nil, :maxlength => 10) %>

notice that we use "nil" here. This is because we want to create a text field with no pre-defined value:

<input id="price" name="price" type="text" maxlength="10" />

If we would have provided a name, Rails would add the HTML attribute "value":

<input id="price" name="price" type="text" maxlength="10" value="my predefined value instead of nil" />

Select boxes:

A common task inside forms is to let the user select something from select boxes - or drop downs. To display a simple select box we can combine some handy methods:

<%= select_tag (:name, options_for_select([['Peter','pete'],['Joseph', 'jo']]))%>

would create

<select id="name" name="name">
 <option value="pete">Peter</option>
 <option value="jo">Joseph</option>
</select>

Another nice helper of the select_* family is select_year. When you want the user to choose his year of birth, you may use something like:

<%= select_year Date.today, :start_year => 2009, :end_year => 1900  %>

This will create a select box with all years, starting from 2009 going to 1900 with the current year (Date.today as the first argument) being pre-selected. Be sure to check out the other helpers for dates Datehelpers

Handling Errors[edit]

Now that you know how to display forms correctly in Rails, we are looking for a way to give the user some feedback over his input. Either if it is correct or if he needs to re-enter some values. You have already read about how to validate form data before it gets written into the database. Now you will see how to display the errors. Basically there are two methods that allow us to display errors: error_messages and error_messages_for. The name gives a pretty good idea of the difference between these two: error_messages displays all errors for the form, while error_messages_for displays the errors for a given model.

Using the methods is easy:

<% form_for(@product) do |f| %>
  <%= f.error_messages %>
    <p>
    <!-- different form tags -->
    </p>
<% end %>

will display all the error messages: either default ones or the ones you have specified inside your model (:message => "Only integers allowed"). error_messages_for is used in a similar manner. Then it display the error message for the field that matches the given name (:name in this case)

<%= error_messages_for :name %>

You can also customize the error messages that are displayed in a box, even more:

<%= f.error_messages :header_message => "Invalid product!", :message => "Correct your entries", :header_tag => :h6 %>

Advanced Forms[edit]

Until now we mainly worked with form elements that have a _tag at the end of the name. When working with a model (e.g. you want to update your data or create a new data set) you want to use the form elements that are more suited for the job. There are no new elements to learn we just use the one we already know but do not add the _tag at the end (compare form_tag and form_for).

Let's asume we want to create a new Product via a form:

We have a controller that has an action... products_controller.rb

#...
def new
  @product= Product.new
end
#...

... and a view (view/products/new.html.erb) that works with our @product instance:

<% form_for :product, @product, :url=>{:action => "create"} do |f| %>
  <%= f.text_field :name %>
  <%= f.text_field :price %, :size => 10 >
  <%= f.text_field :amount%, :size =>5 >
  <%= submit_tag "New Product" %>
<% end %>

will create HTML similar to:

<form action="/products" class="new_product" id="new_product" method="post">
 <div style="margin:0;padding:0">
 <input name="authenticity_token" type="hidden" value="bgqa1sbwcC5J/tIpPtJjX/3slveFNJg3WZntSOyHT4g=" />
 </div>
 <input id="product_name" name="post[name]" size="30" type="text" />
 <input id="product_price" name="post[price]" size="10" type="text" />
 <input id="product_amount" name="post[amount]" size="5" type="text" />
 <input id="product_submit" name="commit" type="submit" value="Update" />
 
</form>

Let's inspect the code: form_for has some code on his side, :product references the name of the model that we want to use and @product is the instance of the object itself (in this case, it's going to be a new product). We loop or "yield" through the form_for object with the variable f. The rest uses code you are already familiar with. We use the action "create" to handle the creation of the file.


Restful Resources[edit]

The methods shown above may not be exactly what you will see in other Rails applications. Most of them will use RESTful resources. This gives Rails the option to decide what to do with the data. This makes the form_for method a lot easier and more readably:

form_for :product, @product, :url=>{:action => "create"}

turns into

form_for (@product)

That is a lot better, isn't it? Now the form_for tag looks the same, no matter if you are creating a new product or if you update an existing one. Rails is smart enough to recognize the action and provides us with the correct HTML attributes (see <form action="/products" class="new_product" id="new_product" method="post">)

To learn more about routing and REST be sure to take a look at Routing.

Using select boxes with a model[edit]

We already learnt how to create select boxes with built in helpers. But you may also want to display the contents of a model inside a select box. To show how this is done, we want to select categories from the database, so the user can select the according one:

<%=f.collection_select :category, :id, Category.all, :name, :name.downcase %>

If you have some categories inside your database the HTML may look similar to

<select id="category_id" name="category[id]">
 <option value="cds">CDs</option>
 <option value="books">Books</option>
 <option value="dvds">DVDs</option>
</select>

Notice the .downcase: this will write the HTML values lowercase, if your database needs to work with it that way. This is just a starting point for your work. To see more examples and explanations, a good start is the official API