Absolute Moron's Guide to Forms in Rails, Part 3 11

Posted by jeff Sunday, April 06, 2008 14:03:00 GMT

Pretzels anyone?

Today we continue our tour of forms in Rails. Parts one and two established these key ideas:

  • Your html.erb templates generate raw HTML form code for the browser.
  • Forms that target a model should use form_for to make life easy.
  • Your routes.rb is used by Rails to transform HTTP requests from the browser into a Ruby hash that’s always called params inside your controller.
  • The params hash is your bridge between the browser and your controller.
  • If you follow simple conventions for the name attribute of your HTML controls, Rails will automatically populate the params hash in ways that make it easy to spoon-feed your models with data.

Let’s continue by learning how to add a check box onto our form.

In Part 1 our form contained a textbox so that we could create a new flight given a flight number. Let’s also indicate if there will be meal service on the flight.

Adding a new column to the Flights table

First we need to add a new attribute to our Flight model. We have two choices for altering the table. We can modify our existing migration file and run the migrations from the beginning (rake db:migrate:reset), but that’s not going to help us if we’ve already deployed this app to production. Let’s say that the app is already deployed, and so we will go ahead and create a new migration file:

script/generate migration AddMealToFlight

or for those on Windows

ruby script\generate migration AddMealToFlight

Open the new migration file and you should have something like this:

class AddMealToFlight < ActiveRecord::Migration
  def self.up
  end

  def self.down
  end
end

Add some code inside the up and down methods to add a boolean column to our table:

def self.up
  add_column :flights, :meal, :boolean, :default => false
end

def self.down
  remove_column :flights, :meal
end

We’ve added a boolean column named meal which will, of course, default to false, because nowadays it seems only flights longer than two days come with free meals.

Finally, update the database:

rake db:migrate

Rails does a nifty thing with boolean columns: it supports the Ruby question mark convention for object attributes that return a boolean Ruby value. Open up your Rails console to see what I mean:

script/console
Loading development environment (Rails 2.0.2)
>> f = Flight.find(1)
=> #<Flight id: 1, number: "123", created_at: "2008-04-05 20:05:24", updated_at: "2008-04-05 20:05:24", meal: false>
>> f.meal?
=> false

Me Want GUI

Now that we have our new column, let’s add a checkbox to our form so that we can set the meal value when we create the flight.

Open up the new.html.erb template again, and use the form builder object to add a checkbox:

<p>
  <%= f.check_box :meal %><b>Meal Service</b>
</p>

Navigate to the form in your browser:

Let’s take a quick look at the actual HTML that got generated. You’ll see some new HTML inside our form:

<p>
  <input id="flight_meal" name="flight[meal]" type="checkbox" value="1" />
  <input name="flight[meal]" type="hidden" value="0" /><b>Meal Service</b>
</p>

The first <input> control is our checkbox. Notice again how it uses the “model[attribute]” convention to help populate the params hash for later processing. If the checkbox is selected, the browser will send the value “1”.

If the checkbox isn’t selected, browsers won’t send “0”. In fact, they won’t send anything at all! This is a problem, because it means that if we were editing this flight, and you unchecked the box to turn off meal service, we would never know it, because the flight[meal] value would not exist in the params hash.

To get around this, the check_box method we used automatically inserts that second, hidden input tag, with the same name but a value of zero. If the checkbox is not checked, this input value will be sent by the browser and our Rails code will update the model accordingly.

Go ahead and check the box, and then click the Create button. You’ll create a new flight, and this time the meal column will have the value true. We can learn how to use the new meal? attribute by opening up the Rails console again and finding our new flight:

>> f = Flight.find_by_number '987'
=> #<Flight id: 2, number: "987", created_at: "2008-04-05 20:24:21", updated_at: "2008-04-05 20:24:21", meal: true>
>> f.meal?
=> true

Ta da! A checkbox that’s hooked up to the meal column, just like we hooked up our textbox to the number column last time. .NET readers may begin to see that form_for is how we do “data binding” in Rails.

Radio Radio

Next time, we’ll be adding some radio buttons to our form. In the meantime, if you have comments or questions on what we’ve done so far, leave us a comment below.

Comments

Leave a response

  1. Justin Camerer   April 07, 2008 @ 12:50 AM

    What browser is that a screen shot of?

  2. Jim Neath   April 07, 2008 @ 08:56 AM

    @Justin: Looks like firefox 3 for the mac. Beta 5 came out last Wednesday (I think)

    http://www.mozilla.com/en-US/firefox/3.0b5/whatsnew/

  3. John Topley   April 07, 2008 @ 08:56 AM

    @Justin

    It's the Firefox 3 beta.

  4. jack   April 09, 2008 @ 06:28 PM

    ok - people enough with the browser comments and questions... give the man some props for the quality tutorials he's producing, not for the browser that someone else made.

    You da man Jeff!

    ps. the browser is nice.

  5. Jeff   April 10, 2008 @ 03:26 PM

    Thanks, Jack. I'm glad somebody saw something other than the screenshots :-)

    (or is that just you again, Mom?)

  6. kino   May 24, 2008 @ 01:06 AM

    Therefore, the pure employment of our knowledge is what first gives rise to the paralogisms of pure reason, since none of our sense perceptions are disjunctive.

  7. Ellroy   May 30, 2008 @ 11:15 PM

    The fundamental form of this universal synthesis (if we maintain this attitude) needs to be criticized with regard to its validity and range, before it can be used for the purposes of a radical grounding of an infinite horizon of approximations by orienting scientific evidence according to accured insights.

  8. Danni   June 03, 2008 @ 02:23 PM

    I’m new to rails and have to implement some kind of user management for this platform we’re developing. I’ve been going through the REST-Tutorials and now these and I have to say: It’s been very informative and so much of a fun read on top of it! You writing style really makes me crack up (to the point where my co-workers are wondering what I’m chuckling about). Thank you very much and keep up the good work! I’m already looking forward to reading the rest of these posts and the Capistrano-Chapter.

    (btw this ain’t yo Mama!)

  9. Arthur Goldsmith   August 01, 2008 @ 10:48 PM

    Hey, this tutorial and the REST tutorial is EXACTLY what people need to be reading before jumping into rails. Helps you understand the fundamentals of the framework. Thanks again.

  10. phil silverweaton   September 24, 2008 @ 11:52 PM

    Okay I have a question. I am trying to add a check box to the form for a model just like this tutorial. However, I don’t need to store the flag in the back-end nor in the model. So how can I get the check box value in that case when there is no auto magical link from form param to model?? I tried and keep failing. Frustrating because this should be simply and work the first time! :)

  11. Jeff   September 26, 2008 @ 07:28 PM

    phil: have you tried a plain check_box_tag ? That will generate a “bare” checkbox without any associated model. See the docs here

Comment


(won't be published)