4

I'm using simple_form to render my forms and trying to get the following behavior: I want the client to choose from 3 options. In every option he supplies additional field or two.
So I'd like something like this:

Please set your preferences:  
 o Pay me on a specific day - [input field to get the day]  
 o Pay me a specific amount of money - [input field for the amount]  
 o Pay me on a regular basis - [radio buttons to choose between weekly/monthly basis]

I can create the radio buttons as follows, but can't add nested fields under them:

<%= simple_form_for @client, action: 'edit_payment_method' do |f| %>
    <%= f.input :payment_type, label: 'Please set your preferences:',
        collection: [ ['Pay me on a specific day', :specific_day],
        ['Pay me a specific amount of money', :specific_money],
        ['Pay me on a regular basis', :regular_basis]
     ], as: :radio_buttons %>

  <%= f.button :submit, 'Submit' %>
<% end %>

What would be the best way to create the nested text boxes?
As for the fields, I don't need to send them to different controllers (per payment_type), it's fine if I send them all to one method and read the relevant values according to the payment type he chose.

Thanks! Zach

2 Answers 2

5

The simple_form collection_radio_buttons is likely what you want. Its options parameter accepts a block which allows you to customize what is rendered with each radio button. Take a look at the example in rdocs here.

Edited:

Here is basically what you need to do in a relatively generic way (hasn't been tested, but I'm running something similar). Put your additional controls in the partial for each radio button:

<% radio_buttons = [
       { :text => 'Pay me on a specific day', :value => :specific_day, :partial => "<textbox_partial_name>", :locals => { :any_locals => :your_partial_needs} },
       { :text => 'Pay me a specific amount of money', :value => :specific_money, :partial => "<textbox_partial_name>", :locals => { :any_locals => :your_partial_needs} },
       { :text => 'Pay me on a regular basis', :value => :regular_basis, :partial => "<radio_partial_name>", :locals => { :any_locals => :your_partial_needs} }, 
  ] %>

<%= simple_form_for @client, action: 'edit_payment_method' do |f| %>
  <%= f.label t("account.update_payment_method.title") %>
  <%= f.collection_radio_buttons :payment_type, (collection.collect do |r| [r[:text], r[:value], r[:partial].nil? ? "" : r[:partial], r[:locals].nil? ? {} : r[:locals]] end), :second, :first do |builder| %>
    <%= builder.label{builder.radio_button(:class => 'payment_method_options') + builder.text} %>
    <% unless builder.object[2].blank? %>
      <%= render :partial => builder.object[2], :locals => builder.object[3] %>
    <% end %>
  <% end %>
  <%= f.button :submit, 'Submit' %>
<% end %>

You can omit :partial for any radio button that doesn't need additional controls, along with :locals if your partial doesn't need it. There are also ways to simplify this code for your situation, but this example illustrates how to add more complex control structures to each radio button if needed.

Sign up to request clarification or add additional context in comments.

2 Comments

I had to use <%= f.collection_radio_buttons ... (added equal sign)
Fixed example as suggested. @ZachMoshe please update accepted answer to this post. Yes, you accepted your own answer, but it isn't correct.
0

OK.. I've managed to solve this somehow, not sure that it's the best alternative, but I'm posting it so if someone needs it in the future he at least has something to start with.

I went with creating a "regular" form using simpleform and then using JQuery to move the inner input fields (which were created regularly) next to the radio buttons.

Add JQuery support to your rails app:

  • add gem "jquery-rails" to your Gemfile
  • bundle install
  • rails generate jquery:install

The form I've used (regular simpleform):

Notice the class that is attached to the radio buttons and the ids that are attached to the input fields. I'll use it later to move the elements.

<%= simple_form_for @client, url: 'update_payment_data' do |f| %>
    <%= f.input :payment_type, label: t('account.update_payment_method.title'),
          input_html: { class: 'payment_method_options' },
          collection: [ [t('account.update_payment_method.sum_based.title'), :amount],
                        [t('account.update_payment_method.days_in_month_based.title'), :days_in_month],
                        [t('account.update_payment_method.optout.title'), :optput]
          ], as: :radio_buttons %>
    <%= f.input :payment_amount, label: "Payment amount threshold", 
          input_html: { id: 'payment_amount_box' } %>
    <%= f.input :payment_days_in_month, label: "Payment days in month", 
          input_html: { id: 'payment_days_in_month_box' } %>
    <%= f.button :submit, t('account.update_payment_method.update') %>
<% end %>

In the same page - the JQuery code:

<script>
    $(document).ready(function() {
        var amount_box = $("#payment_amount_box");
        var amount_box_parent = amount_box.parent();
        amount_box.detach().appendTo($(".payment_method_options:eq(0)").parent());
        amount_box_parent.remove();

        var dim_box = $("#payment_days_in_month_box");
        var dim_box_parent = dim_box.parent();
        dim_box.detach().appendTo($(".payment_method_options:eq(2)").parent());
        dim_box_parent.remove();

    });
</script>

I think it's pretty self-explanatory, it just looks for what is going to be the inner input fields (by id) and moves them into the appropriate place under the span that simpleform creates for each radio button.
I had to play a little bit with the css to make it look how I wanted (display:block for example), but that's more or less it.

Hope it helps.. Zach

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.