Topic: Help me DRY this up

I tried breaking out the remove link section into a helper but couldn't get it working for some reason.  What do you guys suggest?

_phone.rhtml
<div class = "phone">
    <% fields_for model_attributes, phone do |phone_form| %>
        <p>
            Phone Number: <%= phone_form.text_field :phone_number, :index => nil %>
            <% if phone.new_record? %>
                <%= link_to_function "remove", "this.up('.phone').remove()" %>
            <% else %>
                <%= link_to_function "remove", "mark_for_destroy(this, '.phone')" %>
                <%= phone_form.hidden_field :id, :index => nil %>
                <%= phone_form.hidden_field :should_destroy, :index => nil, :class => "should_destroy" %>
            <% end %>
        </p>
    <% end %>
</div>

_address.rhtml
<div class = "address">
    <% fields_for model_attributes, address do |address_form| %>
        <p>
            Address (1): <%= address_form.text_field :address1, :index => nil %>
            Address (2): <%= address_form.text_field :address2, :index => nil %>
            City: <%= address_form.text_field :city, :index => nil %>
            State: <%= address_form.text_field :state, :index => nil %>
            Zip Code: <%= address_form.text_field :zip_code, :index => nil %>
            <% if address.new_record? %>
                <%= link_to_function "remove", "this.up('.address').remove()" %>
            <% else %>
                <%= link_to_function "remove", "mark_for_destroy(this, '.address')" %>
                <%= address_form.hidden_field :id, :index => nil %>
                <%= address_form.hidden_field :should_destroy, :index => nil, :class => "should_destroy" %>
            <% end %>
        </p>
    <% end %>
</div>

Re: Help me DRY this up

def refactored ( value )   
       if " #{value} ".new_record?
                link_to_function "remove", "this.up('." #{value} "').remove()"
       else
                link_to_function "remove", "mark_for_destroy(this, '." #{value} "')"
               " #{value} "_form.hidden_field :id, :index => nil
               " #{value} "_form.hidden_field :should_destroy, :index => nil, :class => "should_destroy"
       end
end

helper method; the syntax may be slightly different, just a quick guess

<%= refactored(:address) %>
<%= refactored(:phone) %>

Re: Help me DRY this up

more like:

def remove_link( record,class, form )   
  if record.new_record?
    link_to_function "remove", "this.up('.#{class}').remove()"
  else
    output = link_to_function "remove", "mark_for_destroy(this, '.#{class}')"
    output << form.hidden_field( :id, :index => nil)
    output << form.hidden_field( :should_destroy, :index => nil, :class => "should_destroy")
    output
  end
end

# Usage
# remove_link(AR object,CSS class of parent, form object)
<%= remove_link(phone, ".phone", phone_form) %>
<%= remove_link(address, ".address", address_form) %>


untested.

Last edited by Duplex (2007-12-19 15:39:15)

Re: Help me DRY this up

@Duplex

thank you, that is certainly more complete;

is there a difference between 'result' and 'output' ?
what principle is behind using 'value' vs '#{value}'?
I assume that is array an string; when to use which ?

Last edited by ediestel (2007-12-19 15:31:35)

Re: Help me DRY this up

output is simply a local variable, the name has no special meaning, i simply used it cos it fits its purpose: output the result of the method.
As it stands for itself (no "output = something" or methods called on it), its content is used as return value.
most simple example:

def test
  true
end

a call to this method this will return true, no "return true" or assigning it to some special result variable nessessary (like e.g. in *urgs* VBA). instead of "true" we could place a variable there and its value would be returned by the method.
def test
  blabla = true
  blabla #will return true
end

Last edited by Duplex (2007-12-19 15:33:33)

Re: Help me DRY this up

in RJS and AJAX helpers, you need to use the 'value' method of a DOM element (e.g. when using the :with option in oberse_field). I guess that'S where you have seen it.
I this case, 'value' is practically a tiny piece of javascript code. As we are writing in ruby, we put it in a simple ruby string. no magic goin on, just a plain old string RJS puts inside the template/sends to the browser where it gets evaluated.

the other one, "#{value}" , would evaluate the ruby variable or method named "value" inside this string.

blabla = "cool"
"this is #{blabla}"
#=> "this is cool"

note that it doesn't work with single quotes ('#{something}')

Edit: after your mentioning of this, i checked my code for the remove_link and corrected 2 quotation errors... check it out ...

Last edited by Duplex (2007-12-19 15:40:02)

Re: Help me DRY this up

Thank you for the explanation;

What is the difference between 'record, class and form in  your example then ?
Why do you use "#{class}", but no "#{}" for 'record' or 'form' ?

Re: Help me DRY this up

it's not used within ""

Re: Help me DRY this up

ok, thank you

Re: Help me DRY this up

I refactored this whole pattern in to a plugin called attribute_fu

Your phone form would end up looking something like this:

_phone.rhtml
<div class = "phone">
  <p>
      Phone Number: <%= f.text_field :phone_number %>
      <%= f.remove_link "Remove" %>
  </p>
</div>

...and you'd render it like this (in the parent model's form):

<%= f.render_associated_form(@user.phone_number) %>

There are some other niceties too... worth a look, in my obviously biased opinion smile.