views:

1286

answers:

4

In my models, there are lots of attributes and methods that perform some calculation based on the model instance's attributes. I've been having the methods return nil if the attributes that the calculations depend on are nil. As a consequence of this design decision, I'm doing a lot of nil checks before displaying these values in my views.

I thought about having these methods return zero instead of nil when they don't have enough information, but I chose nil because zero is a valid computation result and nil implies that there was not enough information.

Should I return 0 instead of nil? Is there any other pattern that I could use to avoid doing a bunch of nil checks in my views?

+7  A: 

I tend to think you are doing things right if your problem is choosing whether to display, or not display, the results of a calculation. If it would make no sense to display any value, then nil is perfectly reasonable.

If, however, your business logic is resulting in you getting into a state where much of the view will be habitually blank, then you probably should refactor such that your program loses its leaky abstractions.

Consider, for example, an application which starts by tracking recipes for Food. Then, as requirements morph, we get the notion of pies needing to display different information than burgers. Rather than having a calculate_deliciousness_of_pie_or_nil_for_burger method, and then checking for nil in the view, I'd break that into a pie view for pies and a burger view for burgers. This might (probably would) require rethinking my object abstractions.

Patrick McKenzie
+2  A: 

This SO question might provide you some insight on the nil or zero pattern:

Best Ruby idiom for “nil or zero”

mwilliams
+2  A: 

"I'm doing a lot of nil checks before displaying these values in my views."

I think returning nil is a good idea. An alternative that I sometimes use is to return a hash. For example, if a method succeeded, I might return:

{:result => 1234}

and if the method "failed", I might return:

{:error => 'Insufficient attributes to calculate result.'}

This makes it trivial to determine the outcome without guessing.

With that said, make sure that you create helper methods to call these methods and check their results. Views should contain very little logic. So rather than doing this to control whether or not the result is displayed:

<% if result = some_method -%>
  Your result is <%=h result -%>.<br />
<% end -%>

You should do this:

<% display_some_method %>

and #display_ some_ method is located in app/helpers/whatever_helper.rb .

nickh
You should use == in the above example.
maurycy
A: 

I attack this problem using two approaches.

I try to move more demanding checks into the model. For instance, method Apartment#address_visible?(current_user) makes it much more cleaner.

Since Rails 2.3 there is also #try method that calls a method only if it is already defined. It can be easily included into your project using chris' example. This is for the most simple cases.

maurycy
if you are not on 2.3 there is also andand http://github.com/raganwald/andand
Mike Breen