155

My question is similar to this one but for a Rails app.

I have a form with some radio buttons, and would like to associate labels with them. The label form helper only takes a form field as a parameter, but in this case I have multiple radio buttons for a single form field. The only way I see to do it is to manually create a label, hard coding the ID that is auto generated for the radio button. Does anyone know of a better way to do it?

For example:

<% form_for(@message) do |f| %>
    <%= label :contactmethod %>
    <%= f.radio_button :contactmethod, 'email', :checked => true %> Email
    <%= f.radio_button :contactmethod, 'sms' %> SMS
<% end %>

This generates something like:

<label for="message_contactmethod">Contactmethod</label>
<input checked="checked" id="message_contactmethod_email" name="message[contactmethod]" value="email" type="radio"> Email
<input id="message_contactmethod_sms" name="message[contactmethod]" value="sms" type="radio"> SMS

What I want:

<input checked="checked" id="message_contactmethod_email" name="message[contactmethod]" value="email" type="radio"><label for="message_contactmethod_email">Email</label>
<input id="message_contactmethod_sms" name="message[contactmethod]" value="sms" type="radio"> <label for="message_contactmethod_sms">SMS</label>
Community
  • 1
  • 1
Bryan
  • 3,453
  • 6
  • 26
  • 20

5 Answers5

246

Passing the :value option to f.label will ensure the label tag's for attribute is the same as the id of the corresponding radio_button

<%= form_for(@message) do |f| %>
  <%= f.radio_button :contactmethod, 'email' %> 
  <%= f.label :contactmethod, 'Email', :value => 'email' %>
  <%= f.radio_button :contactmethod, 'sms' %>
  <%= f.label :contactmethod, 'SMS', :value => 'sms' %>
<% end %>

See ActionView::Helpers::FormHelper#label

the :value option, which is designed to target labels for radio_button tags

John Douthat
  • 40,711
  • 10
  • 69
  • 66
  • 6
    well, this may have 0 votes because it was answered months later, but actually it's the good one. Caveat: you need Rails >= 2.3.3 – tokland Dec 10 '10 at 15:27
  • 3
    this method also renders the `field_with_errors` div when necessary (that doesn't show up when using the `:contactmethod_email` method). this is the correct answer! – caesarsol Dec 03 '14 at 18:26
153
<% form_for(@message) do |f| %>
  <%= f.radio_button :contactmethod, 'email', :checked => true %> 
  <%= label :contactmethod_email, 'Email' %>
  <%= f.radio_button :contactmethod, 'sms' %>
  <%= label :contactmethod_sms, 'SMS' %>
<% end %>
Matt Haley
  • 4,304
  • 4
  • 25
  • 17
  • 98
    There is another way, too: passing a `:value` option to `f.label` will do the same thing. e.g. `<%= f.label :contactmethod, 'SMS', :value => 'sms' %>`. This sets the "for" attribute of the label tag correctly, which makes clicking the label select the appropriate radio button. In the answer above, simply using the `label` helper will cause the "for" attribute to be incorrect when the radio button is created with FormBuilder – John Douthat Nov 05 '10 at 00:06
  • 2
    I just wanted to say that as a newcomer to Rails, I've found this answer the one I keep coming back to. It's the gift that keeps on giving. Well, until I remember the proper syntax anyway... :) – John Gallagher Oct 20 '11 at 19:14
  • also check this if you are looking for setting the `checked` value conditionally http://stackoverflow.com/a/4708921/429521 – Felipe Sabino Aug 11 '12 at 18:59
  • 8
    For future readers, John Douthat has the correct answer to this question. This answer is no longer correct. – superluminary Apr 03 '14 at 14:54
1

If you want the object_name prefixed to any ID you should call form helpers on the form object:

- form_for(@message) do |f|
  = f.label :email

This also makes sure any submitted data is stored in memory should there be any validation errors etc.

If you can't call the form helper method on the form object, for example if you're using a tag helper (radio_button_tag etc.) you can interpolate the name using:

= radio_button_tag "#{f.object_name}[email]", @message.email

In this case you'd need to specify the value manually to preserve any submissions.

user229044
  • 232,980
  • 40
  • 330
  • 338
0

Using true/false as the value will have the field pre-filled if the model passed to the form has this attribute already filled:

= f.radio_button(:public?, true)
= f.label(:public?, "yes", value: true)
= f.radio_button(:public?, false)
= f.label(:public?, "no", value: false)
localhostdotdev
  • 1,795
  • 16
  • 21
0

This an example from my project for rating using radio buttons and its labels

<div class="rating">
  <%= form.radio_button :star, '1' %>
  <%= form.label :star, '☆', value: '1' %>

  <%= form.radio_button :star, '2' %>
  <%= form.label :star, '☆', value: '2' %>

  <%= form.radio_button :star, '3' %>
  <%= form.label :star, '☆', value: '3' %>

  <%= form.radio_button :star, '4' %>
  <%= form.label :star, '☆', value: '4' %>

  <%= form.radio_button :star, '5' %>
  <%= form.label :star, '☆', value: '5' %>
</div>
MIA
  • 373
  • 3
  • 18