Selection boxes

CS290F Fall 2006 - UCSB Computer Science - Thorsten von Eicken

Jump to: navigation, search
  • Reference: some of the examples are adapted from [1].

Let's take the simple restaurants demo from class and add categories for the restaurants, such as chinese, italian, mexican, etc.

We add a simple table and model for the categories using a migration:

  create_table :categories do |t|
    t.column :name, :string
  end
  add_column :restaurants, :category_id, :integer

and now we need to link the two models together:

class Category << ActiveRecord::Base
  has_many :restaurants
end
class Restaurant << ActiveRecord::Base
  ...
  belongs_to :category
  ...
end

In order to generate a drop-down box with all the categories we first need to fetch the categories in our controller action. We'll fetch the categories in alphabetical order so it looks nicer:

  @categories = Category.find(:all, :order => "name")

And now we can add the drop-down selection box into our form (in the _form.rhtml partial):

<p><label for="restaurant_category_id">Category</label><br/>
<%= collection_select(:restaurant, :category_id, @categories, :id, :name) %></p>

Here collection_select does all the work of producing the HTML for us. The first argument tells it which object will be updated with the posted form, and the second argument tells it which field of that object. Here we're telling it that the selection should go into params[:restaurant][:category_id]. Remember that we have the following line in our create and update actions:

  @restaurant = Restaurant.new(params[:restaurant])

But that's not all, Rails also looks into the @restaurant[:category_id] when processing the template in order to determine which item should be selected by default. The items in the drop-down box come from the @categories collection (3rd argument) and we're telling it to invoke the id and name methods on each element to fill out the options. The HTML produced looks something like this:

<p><label for="restaurant_category_id">Category</label><br/>
<select id="restaurant_category_id" name="restaurant[category_id]">
<option value="1">chinese</option>
<option value="2">italian</option>
<option value="4" selected="selected">steak house</option>
<option value="3">thai</option></select></p>

To push the example a bit further, let's assume that the categories are stored in lower case in the database and that you want the drop-down box to show them capitalized. This means we can't simply tell collection_select to show the :name field. Instead, we need to compute something. To do this, we'll use the select method:

<p><label for="restaurant_category_id">Category</label><br/>
<%= select(:restaurant, :category_id,
           @categories.collect{|c| [c.name.capitalize, c.id]}) %></p>

The difference here is that the 3rd argument is an array of tuples. The first is what is displayed in the drop-down box and the second is the corresponding ID that gets sent with the form submission (seems backwards with respect to the collection_select arguments). The generated HTML is identical to above, except that it now reads "Chinese", etc.

Personal tools