Prettier code in views for chained values?

Sometimes in a view I have written wretchedly, ugly code like this:

<%= @person.company.address.city if @person and @person.company and
@person.company.address and @person.company.address.city %>

I’m calling this a chained value. These values can run deep whether
they are the part of an ActiveRecord association (e.g. a child record)
or a simple composite field (e.g. address_city and address_state become
address.city and address.state).

In any case, we have to make sure everything exists before we try to
display a deeply chained value. Otherwise, our app barfs.

Before I go reinventing the wheel, I am wondering how others may have
handled this, perhaps with a generic helper method. I am considering
writing one. I would want it to be pretty to look at, maybe something
along these lines:

<%= chained_value @person.company.address.city %>

Trouble is, I don’t think this will work because I am guessing it will
attempt to resolve the value it intends on passing. I could describe
the chain and handle it with an eval, I guess, but it looks less pretty:

<%= chained_value “@person.company.address.city” %>

The method definition might look something like this:

def chained_value(value_chain, no_value = “”, error_value = “N/A”)

It has a value it displays when the last item in the chain is blank, and
one it displays if it chokes while trying to work it’s way down the
chain.

Your thoughts?
Mario T. Lanza

Hi,

Mario T. Lanza wrote:

Sometimes in a view I have written wretchedly, ugly code like this:

<%= @person.company.address.city if @person and @person.company and
@person.company.address and @person.company.address.city %>

you can try

<%= @person.company.address.city rescue nil %>

That way, if everything’s fine you get the value or else you get
nothing.

regards,

javier ramírez

Thanks, Javier! I knew there had to be a better way.

I did, however, go ahead and solve the problem with this:

def chained_value(no_value = “”, error_value = “N/A”)
begin
value = yield
value.blank? ? no_value : value
rescue
error_value
end
end

alias :cv :chained_value

This allows for one extra thing: a substitute value to use when blank.

<%= cv(“No City”, “No Company Address”){@person.company.address.city} %>

Plus it’s just as concise:

<%= @person.company.address.city rescue nil %>
<%= cv{@person.company.address.city} %>

Alternately:

def chained_value(no_value = “”, error_value = “N/A”)
yield || no_value rescue error_value
end

Contrast

<%= cv(“No City”, “No Company Address”){@person.company.address.city} %>

with

<% @person.company.address.city || “No City” rescue “No Company Address”
%>

Just experimenting with the syntax.