Thursday, July 31, 2014

Rails Radio Button Form Helper or f.radio_button for short

There is an abundance of documentation out there for Ruby and Rails developers, in fact, I often have more trouble narrowing down my searches than finding no answer at all.  However, I also often find that the documentation assumes a level of understanding that a beginner doesn't have.  Recently I spent a couple of hours trying to figure out how to use the radio_button form helper.  There was tons of documentation about radio_button_tag, but not as much about radio_button and the parameters were slightly different.  So I decided to write a short beginners guide to f.radio_button.

Again, I’m a beginner myself so I hope you’ll excuse any misunderstandings and help me correct them.  I’m using Ruby 2.0.0p451 and Rails 4.1.0.

My example will be for a radio button that lets you select a level of recurrence: daily, weekly, monthly, none, and stores that choice, as a string in @meeting.recurrence which we’ll assume is set to “none” to start with.  First up, the basic structure of the helper:

<%= f.radio_button :yourfield, “thevalue”,{options: “withvalues”} %>

My actual implementation:

<%= f.radio_button :recurrence, “none”, {checked: “none”==@meeting.recurrence, onClick: “expand(‘none’)} %>

My form is set up as:

<%= form_for(@meeting) do |f| %>

so “f.” implicitly forces my field names to refer to @meeting.fieldname, so :recurrence is shorthand for: @meeting.recurrence.

The second parameter is the value I want the radio button control to return if this item is selected, so “none” is my result if this value is checked.

The third parameter is a hash of options.  In my case, I have two options that I pass to each button in the group of radio buttons. The first determines if the button is the one checked upon page paint.  It sets the parameter ‘checked‘ = true|false by comparing the data attribute to the selection value.  In this example: “none”.  So if @meeting.recurrence is equal to “none” we get true, if not, we get false.

The second parameter is a javascript function that I want called when this item is clicked.  The function is called ‘expand’ and takes a parameter that tells it which option was clicked, in this case, “none”.
This generates the following html code:

<input checked="checked" id="meeting_recurrence_none" name="meeting[recurrence]" onClick="expand(&#39;none&#39;)" type="radio" value="none" />

Let’s break this down into is constituent parts:


  • Because @meeting.recurrence was equal to “none”, my checked option became “checked: true” which translates in the html to checked=”checked”.  
  • The id is derived from values in the call.  :recurrence (remember, this is short for @meeting.recurrence) becomes meeting_recurrence and then the value “none” gets concatenated to give us “meeting_recurrence_none”.  
  • The name similarly is derived from @meeting.recurrence and becomes meeting[recurrence].  Note that this field, the name, is common across all the buttons in your radio button group and is how the application knows they are part of the same set.
  • My onClick hander just gets passed in directly.
  • The type is implied by the radio_button helper.
  • Finally, the return value is set directly from the second parameter, the value.
Now we need to tell the user what this radio button is so we will pair it with a label.  This is the syntax for a label helper.

<%= f.label :yourfield, "thestring", :value => "thevalue" %>

And here is the actual implementation for the label that matches my radio button.

<%= f.label :recurrence, "none", :value => "none" %>

And the HTML that generates:

<label for="meeting_recurrence_none">none</label>

Again, you can see that :recurrence and the value become “meeting_recurrence_none”  which is how this label is tied to the radio button field by its ID.  This allows the label to be clickable as part of the radio selection.  The “thestring” parameter becomes the string shown to the user.

Now here is the whole block I set up for my four options in my radio button group complete with their labels.

<%= f.radio_button :recurrence, "daily", {checked: "daily" == @meeting.recurrence, onClick: "expand('daily')"} %>
<%= f.label :recurrence, "Daily", :value => "daily" %>

<%= f.radio_button :recurrence, "weekly", {checked: "weekly" == @meeting.recurrence, onClick: "expand('weekly')"} %>
<%= f.label :recurrence, "Weekly", :value => "weekly" %>

<%= f.radio_button :recurrence, "monthly", {checked: "monthly" == @meeting.recurrence, onClick: "expand('monthly')"} %>
<%= f.label :recurrence, "Monthly", :value => "monthly" %>

<%= f.radio_button :recurrence, "none", {checked: "none" == @meeting.recurrence, onClick: "expand('none')"} %>
<%= f.label :recurrence, "None", :value => "none" %>

This results in the following final block of HTML being rendered:

<input id="meeting_recurrence_daily" name="meeting[recurrence]" onClick="expand(&#39;daily&#39;)" type="radio" value="daily" />
<label for="meeting_recurrence_daily">Daily</label>

<input id="meeting_recurrence_weekly" name="meeting[recurrence]" onClick="expand(&#39;weekly&#39;)" type="radio" value="weekly" />
<label for="meeting_recurrence_weekly">Weekly</label>

<input id="meeting_recurrence_monthly" name="meeting[recurrence]" onClick="expand(&#39;monthly&#39;)" type="radio" value="monthly" />
<label for="meeting_recurrence_monthly">Monthly</label>

<input checked="checked" id="meeting_recurrence_none" name="meeting[recurrence]" onClick="expand(&#39;none&#39;)" type="radio" value="none" />
<label for="meeting_recurrence_none">None</label>

Finally, to bring it home, this is the data that gets submitted to the server for this control:

"meeting"=>{"recurrence"=>"daily"}

I hope that some other beginner might find this just a little bit helpful.

1 comment:

  1. thank you i also do have the same problem your post halp me a lot

    ReplyDelete