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?
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.
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
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?
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.
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.
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: