Wednesday, January 2, 2008

Radio Buttons

RoR is lovely when it comes to supplying frontend helpers. For example, if you want to create a form for a particular object, it's very simple:

<% form_for :user, :url => new_user_path do |f| %>
...
<% end %>

Inside "...", you can add all your fields, such as:

First name: <%= f.text_field :first_name %>
Last name: <%= f.text_field :last_name %>
...
<%= submit_tag 'Update' %>

This creates a form using the user object. It fills in the first and last names using the data found in the user object. If the user object is new, then the text fields are empty. If the user object is from database, then that information is displayed. Pressing the submit button submits the form to the specified url. It's very simple! There are helpers do to all sorts of things, such as text areas, selects, date selects, time selects, checkboxes, etc. Check the API for more helpers.

However, our topic for today is actually radio buttons. Many times, we want to use radio buttons to select some sort of true/false field. It is possible to do this with checkboxes, andRoR is wonderful with this. However, sometimes, 2 radio buttons are better. This is where I ran into some problems. Reading the API, I came up with 2 radio buttons as follows:

<%= f.radio_button :is_good, true %>
<%= f.radio_button :is_good, false %>

I thought that this would generate two radio buttons with values true/false respectively. However, it didn't! The first generated one that had a value of "true" and was checked. But the second generated a radio button with no value! I then changed the given values from booleans to strings:

<%= f.radio_button :is_good, 'true' %>
<%= f.radio_button :is_good, 'false' %>

Everything worked fine now, but given a model that held data, neither radio buttons were checked! This is due to the fact that the model holds boolean values, whereas the radio buttons use string literals. Saving was fine because we were using prepared statements, which automatically convert the string literals to boolean. I was completely stumped on the displaying of data though. I came up with a quick hack using virtual attributes, but it's ugly:

def is_good_temp=(is_good_temp)
@is_good_temp = is_good_temp
if @is_good_temp == 'true'
self.is_good = true
else
self.is_good = false
end
end

def is_good_temp
@is_good_temp.nil? ? 'true' : @is_good_temp
end

def is_good
@is_good.nil? ? true : @is_good
end

def is_good=(is_good)
@is_good = is_good
end

and changed the radio buttons to:

<%= f.radio_button :is_good_temp, 'true' %>
<%= f.radio_button :is_good_temp, 'false' %>

So basically what I did was create a virtual attribute to deal with the radio buttons using string literals, and have that convert the string literals to booleans and assign it to the actual variable. To be noted is that there is no nice function object#to_b to convert a string literal to boolean. There are nice functions like object#to_s and object#to_i, but not to boolean.

This is one disappointment from RoR. I have searched around and could find no solution to this. Perhaps I am doing this wrong, but for now, it works.

Any ideas would be appreciated, and I'll update if I find a better solution.


W

No comments: