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 %>