views:

53

answers:

2

I'm developing a simple rails app for my own use for learning purposes and I'm trying to handle 2 models in 1 form. I've followed the example in chapter 13 of Advanced Rails Recipes and have got it working with a few simple modifications for my own purposes.

The 2 models I have are Invoice and InvoicePhoneNumber. Each Invoice can have several InvoicePhoneNumbers. What I want to do is make sure that each invoice has at least 1 phone number associated with it. The example in the book puts a 'remove' link next to each phone number (tasks in the book). I want to make sure that the top-most phone number doesn't have a remove link next to it but I cannot figure out how to do this. The partial template that produces each line of the list of phone numbers in the invoice is as follows;

<div class="invoice_phone_number">
  <% new_or_existing = invoice_phone_number.new_record? ? 'new' : 'existing' %>
  <% prefix = "invoice[#{new_or_existing}_invoice_phone_number_attributes][]" %>

  <% fields_for prefix, invoice_phone_number do |invoice_form| -%>
    <%= invoice_form.select :phone_type, %w{ home work mobile fax } %>
    <%= invoice_form.text_field :phone_number %>
    <%= link_to_function "remove", "$(this).up('.invoice_phone_number').remove()" %>
  <% end -%>
</div>

Now, if I could detect when the first phone number is being generated I could place a condition on the link_to_function so it is not executed. This would half solve my problem and would be satisfactory, although it would mean that if I actually wanted to, say, delete the first phone number and keep the second, I would have to do some manual shuffling.

The ideal way to do this is presumably in the browser with javascript but I have no idea how to approach this. I would need to hide the 'remove' link when there was only one and show all 'remove' links when there is more than one. The functionality in the .insert_html method that is being used in the 'add phone number' link doesn't seem adequate for this.

I'm not asking for a step-by-step how-to for this (in fact I'd prefer not to get one - I want to understand this), but does anyone have some suggestions about where to begin with this problem?

Thanks.

+1  A: 

For your problem of detecting whether a row is the first one or not, you could add a local variable when calling the partial:

<%= render :partial => 'mypartial', :locals => {:first => true}  %>

As it would be much easier to detect in the main file, whether a row is the first or not I guess.

Instead of detecting whether a phone number is the first, you could also detect whether a phone number is the only one. If not, add remove links next to all numbers otherwise, do not display the remove link. Note that besides showing/hiding the link, you also need to add code, to prevent removing of the last number by (mis)using an URL to directly delete the number instead of using your form.

Veger
+2  A: 

There is a counter for partial-collections:

<%= render :partial => "ad", :collection => @advertisements %>  

This will render "advertiser/_ad.erb" and pass the local variable ad to the template for display. An iteration counter will automatically be made available to the template with a name of the form partial_name_counter. In the case of the example above, the template would be fed ad_counter.

Nils Riedemann
Oh nice, did not know that!
Veger
Thanks, with a bit of fiddling I've got that working. Looks like a very useful technique I will be able to use elsewhere. It's a good temporary fix for my problem, but doesn't address the issue of leaving the first phone number un-delete-able (which strikes me as something to solve in javascript). Thanks though.
brad