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!