Rails Select Helper

One of the major benefits of Ruby on Rails is rapid development. Something that we love at BadPopcorn. Rails has great helper methods to minimize code and bugs. One of my favorites is the select helper. There are several different ways to make a select tag, but I am going to demonstrate the one I like best. Let's say you are creating a new "gym member". He will have a name and belong to a gym.


1 <%= form_for(@member) do |f| %>
2   <%= f.text_field :name %>
3   <%= select :member,:gym_id,Gym.find(:all).collect{|p| [p.name, p.id]}%>
4   <%= f.submit "Create" %>
5 <% end %>
Line 1 builds the form. Rails uses the @member variable to generate the action, id, and name of the form.
<form id="new_member" class="new_member" action="/members" method="post">
Notice the do | f | code in the form deceleration (line 1). You can now use the local variable f to bind attributes of member to input variables. Line 2 of the code generates the below html. The name of the input variable is a Rails convention.
<input id="member_name" name="member[name]" size="30" type="text" />
Line 3 is the Rails select tag helper. The select tag generates the html select tag cleanly. The name of the select is dynamically created by using the first two parameters of the helper function :member and :name. The options are generated by the third parameter.
<select id="member_gym_id" name="member[gym_id]">
   <option value="1">Get Ripped Here</option>
   <option value="2">Hot Girls Welcome</option>
Line 4 creates the html submit button.
<input id="member_submit" name="commit" type="submit" value="Create" />

Also, Rails will throw an exception if you attempt to bind to a member attribute that does not exist.

For example,
<%= f.text_field :height %>

will throw the exception: undefined method `height' for #. Changing the "gym_id" parameter in the select helper will cause the same type of exception. This will save you from making dumb mistakes time and time again.

So what's posted?

This is where the rails form helper tags come in useful. An organized list of Member was passed as a post parameter to the controller.

Parameters: {"commit"=>"Create", "member"=>{"name"=>"moe", "gym_id"=>"1"},
"action"=>"create", "controller"=>"members"}


When the form is posted it will hit the "create" function in the members controller by default. You can change where it will post to if necessary.

1 def create
2   @member = Member.new(params[:member])
3   respond_to do |format|
4     if @member.save
5       flash[:notice] = 'Member was successfully created.'
6       format.html { redirect_to(@member) }
7     end
8   end
9 end

Line 2 makes a new instance of Member and passes the post parameter member list in the constructor. This returns a member object with the name and gym_id set properly. Line 4 saves the new member in the database.

Member Create (0.000386)   INSERT INTO members ("name", "updated_at",
"gym_id", "created_at") VALUES('moe', '2008-09-02 02:00:35', 1,
'2008-09-02 02:00:35')

The same type exception(s), discussed earlier, will occur here. For example, an exception will be thrown if there is a "height" attribute in the members post parameter.

How we saved time (the short list)

  1. Initially we didn't have to pass much to the view. Just an instance of Member.
  2. We were able to use the Rails html helper to build the correct form quickly.
  3. Rails conventions made it easy to know where the post would be directed to within the controller.
  4. In two lines we created a new Member instance, updated the values with the posted parameters and updated the database.
  5. It's also worth noting that the Rails error checking, when using the helper tags, saves us a lot of debugging time.

What's Next?

Input validation. Making sure the user isn't inputting dumb data. For example, in the above code the user could use undesirable characters in their name. Yup, that's super simple too.