开发者

Handling nil (null) values in nested relations in Rails 2.3.x

The project currently I'm working has the following code in the view:

<%= product.provider.name %>

The above code is get the 'provider' for a product and display his开发者_如何学JAVA/her name. But my question was sometimes this code fails when'provider' gets nil. (I know it's little unusual but since I'm working with a legacy db this happens)

So to check the nil validation I have written the following code (in my ApplicationHelper)

def t(obj, attr)
    obj.nil? ? "" : obj.send(attr.to_sym)
end

Now what I do is something like this:

<%= t(product.provider, "name") %>

Even though this works, I ran in to another problem, I found this code:

<%= product.provider.provider_type.title %>

The problem here is, in the above code either 'provider' or 'provider_type' can be nil.

What I'm looking at is an exception handling mechanism to handle any number of nested relationship.

Or is this a completely wrong path to handle nil values in nested relations? I'm running on Rails 2.3.8.


This is a common problem. You might want to check these:

  • Object.try
  • andand

Examples:

# With try
product.provider.try(:name)
product.provider.try(:provider_type).try(:title)

# With andand
product.provider.andand.name


You can rescue all exceptions:

<%= product.provider.provider_type.title rescue nil %>


since we can use #try methods or handle the exceptions inline, this method of usage breaks the Law of Demeter: Each unit should have only limited knowledge about other units: only units "closely" related to the current unit.

views should get the ready-to-use ojbects/variables, not chains. so you can try to use delegate method within models and cover other else with helpers. keet your views as clean as possible, look at them from designer's point of view.


I solved the problem this way:

class Object
  def unless_nil(default = nil, &block)
    if nil?
      default
    else
      block[self]
    end
  end
end

product.provider.unless_nil(&:name)
product.provider.unless_nil(&:provider_type).unless_nil(&:title)
product.provider.unless_nil("Not specified", &:name)

It is also quite convenient to have Object#unless_blank, Array#unless_empty, Hash#unless_empty.

Added:

Meanwhile using full block is even more convenient in some cases:

some_variable = 
  product.provider.unless_nil do |provider|
    # some complex logic here using provider
  end

I like it more than:

provider = product.provider
some_variable = 
  if provider
    # ...
  end

or using product.provider everywhere. Matter of taste though.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜