Nested Attributes and Radio Buttons -- any way to do this?

I have the following:

class Title   has_many :roles   has_many :people, :through => :roles   accepts nested_attributes_for :roles

(Roles and People are also correctly defined)

In my title#edit view, I have the fields_for set up correctly and working:

<%= f.fields_for :roles do |builder| %> <%= render "role_fields", :f => builder %> <%- end -%>

and in the role_fields partial, I have

<%= f.check_box :primary %> <%= f.label :primary %>

Now I would like to change the check_box (which does work correctly) into a radio button, so only one of the nested roles would be the primary role. How can I use nested attributes and radio buttons?

If I replace the f.check_box call with f.radio_button( :primary, true ) I end up with a radio group that acts like a bunch of individual radio groups -- I can click on any of them and each one will check on without deselecting any of the others. If I change the name, so that each button has the same name, then the radio group works as expected, but the nested form breaks. I need those unique index names (title[roles_attributes][0][primary], title[roles_attributes][1][primary], title[roles_attributes][3][primary], etc.) to set the primary attribute on the correct nested role.

Short of using JavaScript to enforce the one-radio-button-at-a-time rule here, is there any way to do a nested form with radio buttons like this?

Thanks in advance,

Walter

I'd recommend creating an attr_accessor for :primary on your Title model. In your form you could do something like: f.object.roles.each do |role|   f.radio_button :primary, :role.id   f.label :primary

which should have the desired behavior.

Samantha John wrote in post #1032986:

I'd recommend creating an attr_accessor for :primary on your Title model. In your form you could do something like: f.object.roles.each do |role|   f.radio_button :primary, :role.id   f.label :primary

which should have the desired behavior.

This solution does not work with newly added nested objects as they don't have an ID yet (with cocoon/railscasts way nested forms handling).

I've asked a question about the same issue here :

I ended up solving this in my application by using an after_create hook to set the primary person to whichever person was added first, and then allowing the radio button to change this during any subsequent edit. The radio buttons are not even shown until the parent record is persisted. Not a perfect solution, but one that has actually fit into the workflow very nicely, since the (human) editor seems to think that way (adding the author first) while creating new titles.

Walter

Walter Davis wrote in post #1090281:

don't have an ID yet (with cocoon/railscasts way nested forms handling).

I've asked a question about the same issue here :

I ended up solving this in my application by using an after_create hook to set the primary person to whichever person was added first, and then allowing the radio button to change this during any subsequent edit. The radio buttons are not even shown until the parent record is persisted. Not a perfect solution, but one that has actually fit into the workflow very nicely, since the (human) editor seems to think that way (adding the author first) while creating new titles.

Walter

Seems that you're the same person who answered on Stackoverflow ;o)

This workaround is unfortunately not compatible with my workflow since my app has to be simple and fast...users will not accept a second edit to set the main address...

The sad thing is that this is really easy to do in a hand-made form...but I can't get rid of nested forms that brings lots more than this little issue!

I'm working on a JS workaround, handling "virtual" radio buttons groups, based on "data-radio-group" attribute instead of "name".

This is not as clean as I'd like but it's compatible with my workflow, and logical for the user...

In case someone is interested, here is my really simple code to handle virtual radio buttons groups (it's Coffeescript + jQuery) :

jQuery ->   $("input[data-radio-group]").on 'change', (e) ->     $("input[data-radio-group='" + $(e.target).data('radioGroup') + "']").attr('checked', false)     $(e.target).attr('checked', true)

When you change an input with "data-radio-group" arttributes, it unchecks other inputs with same group value and checks the one changed (so that you can't unselect all options).

Compared to "real" radio groups, I loose the ability to quickly get the "group value" but I don't need that in my case.

You might try this:

  $$('input[data-radio-group="foo"][checked]').first().getValue();

That's Prototype, but you should be able to translate to jQuery -- they both use Sizzle under the hood, and the selector's the thing that matters here.

Walter

Compared to "real" radio groups, I loose the ability to quickly get the "group value" but I don't need that in my case.

You might try this:

  $$('input[data-radio-group="foo"][checked]').first().getValue();

Or maybe it's

  $$('input[data-radio-group="foo"]:checked').first().getValue();

Try both.

Walter

The second selector is correct. Converting it to jQuery, it’s

$(‘input[data-radio-group=“foo”]:checked’).first().val();