Really, and I mean really easy question

Hello everybody,

Quick question. Let's say I have model Person and has a belong_to
relationship to model Award through award_id. As you can imagine a
person may have no award. If I just say in the template:

<%= @person.award.name %> I will get the annoying 'nil' error when the
template is rendered if the person does not have an award -- and I
have a lot of similar situations in my template. I could write:

<%= @person.award.name if @person.award %>, I guess, but is this the
best way to do it?

Thanks!

I would create a helper to display what information you want, pass in
the person and then return the award name or nothing. So for example
in your helper you would have:

def show_award_name(person)
   unless person.award.name.blank?
     person.award.name
   else
     "NA"
  end
end

then in your view i would do:

<%= show_award_name(@person) %>

This would clean up your view and allow you to use if statements. Of
course you would need to modify this for a many awards situation.

-Chris

That's what I do, unless it's one particular thing that comes up often. If so, then in the Person model I'd make an award_name method that handled the nil case. Then the view would be

<%= @person.award_name %>

A more ambitious programmer might write a more generic equivalent, which perhaps you'd call as

<%= @person.award_field(:name) %>

You could use raganwald's andand gem. With it you could write:

    <%= @person.award.andand.name %>

See http://andand.rubyforge.org/

Stefan

surge wrote:

Hello everybody,

Quick question. Let's say I have model Person and has a belong_to
relationship to model Award through award_id. As you can imagine a
person may have no award. If I just say in the template:

<%= @person.award.name %> I will get the annoying 'nil' error when the
template is rendered if the person does not have an award -- and I
have a lot of similar situations in my template. I could write:

<%= @person.award.name if @person.award %>, I guess, but is this the
best way to do it?

Thanks!

You could say

<%= @person.award.name.nil? ? '' : @person.award.name %>

That way if it was nil nothing would be displayed (which may or may not
be what you want) but no error message will be thrown. I like this way a
lot better then using 'if'.

Thanks for your replies, everybody. Because I have too many of these
fields, I'm not too crazy about writing helper methods. I got this
suggestion from somebody:

<%= @person.award.name rescue nil %> and I like the shortness of it.

But I really do appreciate your suggestions!

If you have many fields from the award, you can wrap the whole thing in an if block

<% if person.award %>

...several lines of award display code

<% else %>

some other display when there's no award

<% end %>

I've cloned the groovy nils behaviour into my rails app by simply
adding
groovy_nils.rb into congif/initializers

While this might deal with the simple case of removing some tedium
from a view, I really think you're setting yourself up for a hard to
diagnose problem further down the line.
Either through not checking or through some exceptional condition you
end up with a nil instead of what you expected. Instead of failing
there and then your code continues silently until something really bad
happens.

Fred

Hey,

yeah I thought the exact same thing. You have to be carefull when doing
it that way. But for now, I love it. The risk of having some more work
debugging the code when I make a mistake is worth it.

Its not just about the views.
Long association chains? No problem...
if @user.address.street.abutters.first.company
   ...
end

Iterating over something? dont have to check for nil:
@user.sister.neighbors.each do |i|
    sisterneighbors ||= []
    sisterneighbors << i
end
sisterneighbors.dosomething

While unsure at first, I found that it simply "works". Using it for
quite some time now and dont found a situation where it could break
alot.

Like the Groovy Nils solution, this trades brevity for correctness: if
you ever have another type of error--like a database problem where the
name column is missing or if you accidentally type nmae--you will
silently ignore the problem. This may be acceptable to you.

If you want a round-up of solutions, on my original blog post I tried
to summarize the approaches people have described to this common
issue. You may find them interesting:

http://weblog.raganwald.com/2008/01/objectandand-objectme-in-ruby.html

This pattern might work for you:

class Award
  def to_s
    name
  end
end

<%= @person.award %>