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| %>
<%= 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('none')"
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('daily')" type="radio"
value="daily" />
<label
for="meeting_recurrence_daily">Daily</label>
<input
id="meeting_recurrence_weekly" name="meeting[recurrence]"
onClick="expand('weekly')" type="radio"
value="weekly" />
<label
for="meeting_recurrence_weekly">Weekly</label>
<input
id="meeting_recurrence_monthly" name="meeting[recurrence]"
onClick="expand('monthly')" type="radio"
value="monthly" />
<label
for="meeting_recurrence_monthly">Monthly</label>
<input
checked="checked" id="meeting_recurrence_none"
name="meeting[recurrence]"
onClick="expand('none')" 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"}