views:

3033

answers:

7

This is one of those things, that maybe so simple I'll never find it because everyone else already knows it.

I've got objects I have to check for nil in my views so I don't dereference a nil:

<%= if tax_payment.user; tax_payment.user.name; end %>

Or I could do this variant:

<%= tax_payment.user ? tax_payment.user.name : '' %>

So this is ok ... for most languages. But I feel like there must be some bit of shiny ruby or railness I'm still missing if this is the best I can do.

+14  A: 

What about:

<%= tax_payment.user.name if tax_payment.user %>
Ben Alpert
I knew it would be a head slapper, thanks.
Jeremy
+12  A: 

You can also try the new Object.try syntax, pardon the pun.

This is in the shiny new Rails 2.3:

tax_payment.try(:user).try(:name)
Toby Hede
Cool that is also like what I was looking for, I look forward to that release.
Jeremy
+5  A: 

For a little more comprehensive solution, you could check out the Introduce Null Object Refactoring. The basic mechanics of this refactoring is that instead of checking for nil in the client code you instead make sure that the provider never produces a nil in the first place, by introducing a context-specific null object and returning that.

So, return an empty string, an empty array, an empty hash or a special empty customer or empty user or something instead of just nil and then you will never need to check for nil in the first place.

So, in your case you would have something like

class NullUser < User
    def name
        return ''
    end
end

However, in Ruby there is actually another, quite elegant, way of implementing the Introduce Null Object Refactoring: you don't actually need to introduce a Null Object, because nil is already an object! So, you could monkey-patch nil to behave as a NullUser – however, all the usual warnings and pitfalls regarding monkey-patching apply even more strongly in this case, since making nil silently swallow NoMethodErrors or something like that can totally mess up your debugging experience and make it really hard to track down cases where there is a nil that shouldn't be there (as opposed to a nil that serves as a Null Object).

Jörg W Mittag
A: 

I just do

<%= tax_payment.user.name rescue '' %>
Matt Darby
A: 

I do:

<%= tax_payment.user.name || '' %>

This seems the cleanest and simplest to me.

The Wicked Flea
You'll get a nil object error when user is nil.
Jeremy
Good point. I haven't used it that deep. But it also depends on the page logic, the page may never get to that point because a payment requires a user. Etc. So, there are some failsafes to consider BEFORE voting me down.
The Wicked Flea
The things about the "failsafes" you mention is that they too sometimes fail.
Nick
Sure. So check the failsafe and the input. Ensure that output is fine that way, or redirect to an error page.
The Wicked Flea
+1  A: 

The Ruby community has put an incredible amount of attention to automating this idiom. These are the solutions I know of:

The most well-known is probably the try method in Rails. However, it has received some criticism.

In any case, I think Ben's solution is perfectly sufficient.

Antti Tarvainen
+1  A: 

Another option, which makes sense occasionally...

<%= tax_payment.user && tax_payment.user.name %>

If tax_payment.user returns nil, nil.to_s (an empty string) is printed, which is harmless. If there is a user, it will print the user's name.

Jeremy Weiskotten