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.
-
What about:
<%= tax_payment.user.name if tax_payment.user %>
Jeremy : I knew it would be a head slapper, thanks. -
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)
Jeremy : Cool that is also like what I was looking for, I look forward to that release. -
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 anil
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 fornil
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-patchnil
to behave as a NullUser – however, all the usual warnings and pitfalls regarding monkey-patching apply even more strongly in this case, since makingnil
silently swallowNoMethodError
s or something like that can totally mess up your debugging experience and make it really hard to track down cases where there is anil
that shouldn't be there (as opposed to anil
that serves as a Null Object). -
I just do
<%= tax_payment.user.name rescue '' %>
-
I do:
<%= tax_payment.user.name || '' %>
This seems the cleanest and simplest to me.
Jeremy : You'll get a nil object error when user is nil.The Wicked Flea : 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.Nick : The things about the "failsafes" you mention is that they too sometimes fail.The Wicked Flea : Sure. So check the failsafe and the input. Ensure that output is fine that way, or redirect to an error page. -
The Ruby community has put an incredible amount of attention to automating this idiom. These are the solutions I know of:
- try in Ruby on Rails
- Another try
- andand
- A safer andand
- Kernel::ergo
- send-with-default
- maybe
- _?
- if-not-nil
- turtles!
- method_ in Groovy style
- do-or-do-not
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.
-
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.
0 comments:
Post a Comment