Best way of handling nils in views?

I find myself writing ugly code like the following a LOT:

<td><%=emp.title%></td>
<td><%=emp.department.name if !emp.department.nil? %></td>
<td><%=emp.site.name if !emp.site.nil?%></td>
<td><%=if (!emp.site.nil? and (!emp.site.phone.nil? or !
emp.site.phone.empty?))
          emp.site.phone
        else
          "&nbsp;"
        end%>
</td>

Notice all those nil? checks? Is there no easier or cleaner way of
doing this?

Thanks,
Jake

Or...if you use table borders, you end up doing an even uglier
solution to avoid non-rendered cells for empty contents in Gecko-based
browsers (like Firefox):
<tr>
      <td><%=emp.last_name || "&nbsp;"%></td>
      <td><%=emp.first_name || "&nbsp;"%></td>
      <td><%=emp.title || "&nbsp;" %></td>
      <td><%=if !emp.department.nil?: emp.department.name else
"&nbsp"; end %></td>
      <td><%=emp.site.name if !emp.site.nil?%></td>
      <td><%=if (!emp.site.nil? and
                 (!emp.site.phone.nil? and !emp.site.phone.empty?))
               emp.site.phone
             else
               "&nbsp;"
             end%>
      </td>
      <td><%=emp.extension || "&nbsp;" %></td>
      <td><%=emp.mobile || "&nbsp;"%></td>
      <td><%=emp.pager|| "&nbsp;"%></td>
      <td><%=emp.alternate_phone|| "&nbsp;"%></td>
    </tr>

I find myself writing ugly code like the following a LOT:

<td><%=emp.title%></td>
<td><%=emp.department.name if !emp.department.nil? %></td>
<td><%=emp.site.name if !emp.site.nil?%></td>
<td><%=if (!emp.site.nil? and (!emp.site.phone.nil? or !
emp.site.phone.empty?))
         emp.site.phone
       else
         "&nbsp;"
       end%>
</td>

Notice all those nil? checks? Is there no easier or cleaner way of
doing this?

Well, you could disable the whiny nil in config/environments/.... or you could fix them in the controller/model before they get to your view, or you could do one of these which is a little nicer:

obj.attr unless obj.attr.nil?
obj.attr rescue '&nbsp;'

You might also try .blank? instead of .nil? in your &nbsp; cases.

-philip

I find myself writing ugly code like the following a LOT:

<td><%=emp.title%></td>
<td><%=emp.department.name if !emp.department.nil? %></td>
<td><%=emp.site.name if !emp.site.nil?%></td>
<td><%=if (!emp.site.nil? and (!emp.site.phone.nil? or !
emp.site.phone.empty?))
          emp.site.phone
        else
          "&nbsp;"
        end%>
</td>

Notice all those nil? checks? Is there no easier or cleaner way of
doing this?

Hmm, perhaps one of those "message-eating nils" [1] might have a place here:

  class Object
    def blanker
      Blanker.new(self)
    end
  end

  class Blanker
    instance_methods.each{|name| undef_method(name) unless name =~ /\A__/}
    def initialize(receiver)
      @receiver = receiver
    end
    def to_s
      @receiver.to_s
    end
    def method_missing(*args)
      unless @receiver.nil?
        @receiver = @receiver.send(*args)
      end
      self
    end
  end

Now, <%= emp.blanker.department.name %> should do what you want.

A few other points:

<td><%=if (!emp.site.nil? and (!emp.site.phone.nil? or !
emp.site.phone.empty?))
          emp.site.phone
        else
          "&nbsp;"
        end%>
</td>

activesupport lets you replace (foo.nil? || foo.empty?) with
foo.blank? (I'm assuming you typo'd the logic a bit there...)

That gets us to:

  <td><%=if !emp.site.nil? && !emp.site.phone.blank?
            emp.site.phone
          else
            "&nbsp;"
          end%>
  </td>

As for the '&nbsp;' thing, you might like to define an #or_nbsp method:

  class Object
    def or_nbsp
      str = to_s
      str =~ /\S/ ? str : '&nbsp;'
    end
  end

Which gets us to:

  <td><%=(emp.site && emp.site.phone).or_nbsp %></td>

Or, combining with the #blanker thing above:

  <td><%=emp.blanker.site.phone.or_nbsp %></td>

Thanks,
Jake

Welcome!
George.

[1] http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/17785

AS a general "good practice" (skinny controller & views, fat model)
this is more for the Business logic job:
theres a very conveniant function called delegate. Here's more info
about it :
http://brian.maybeyoureinsane.net/blog/2006/12/15/law-of-demeter-or-how-to-avoid-coding-yourself-into-a-corner-in-rails/

Hi Charly,

Thanks for the link.

Yeah, that's a good point about Demeter; I guess that's another
oft-cited reason to discourage the message-eating-nil thing.
Unfortunately though, #delegate won't check for nils. Not that you
couldn't define your own variant which does easily enough.

George.

This doesn’t sound right in my own ears but I can’t put my finger on
why. What if the method_missing in Nil was replaced by something
like

class Nil

def method_missing( method, *args, &block )

nil

end

end

This way if there is a nil at any point along the chain at the end it
will be a nil. Eg, if department is nil, name will also return nil

<%= emp.department.name || “No Department Set” %>

Just a thought, but is there anything wrong with this approach?

You could take a look at the Null Object pattern, if appropriate for
your model. I've find this quite handy in my RoR apps. A link with an
implementation for active record associations below:

http://blog.craigambrose.com/articles/2006/09/22/active-record-associations-and-the-null-object-pattern

Cheers,
Roland

Roland,

Thanx for the link, I noticed in the comments that Craig has shown nil
chaining as well but distances himself from it. This confirms my
suspicion that there may be something wrong with doing this but for the
life of me I don’t know what.

Cheers

Daniel

It's been discussed at length before:

  http://rubyurl.com/S8A

I think the main argument is it can hide errors easily (or make them
harder to track down). For example, if you typo'd a method name, it'd
treat it the same as if the attribute was nil.

Regards,
George.

Thanx for the link. That was a great thread on the subject.

This works nicely. Thanks George!