假设我有一个User对象,它有一个电子邮件属性,我需要他们的电子邮件的上一个字母:
u = User.find(1) letter = u.email.upcase.last
如果你或者电子邮件在这个链中是零,那么我得到一个NoMethodError:未定义的方法’blah’为nil:Nilclass.在大多数情况下,我应该可以解决这个问题,但有时候,nil应该在不应该包含的地方或者很难包含它.一种方法是冗长的:
u = User.find(1) letter = nil if u && u.email letter = u.email.upcase.last end
但是这在视图中或在a.bunch.of.properties.down.a.hierarchy的长链中变得烦人且危险.我在Rails中读到了关于try方法的内容:
u = User.find(1) letter = u.try(:email).try(:upcase).try(:last)
这不那么冗长,但我觉得写这些尝试都很蠢.一旦我尝试了链条,我就必须一直使用它们.有没有更好的办法?
解决方法
我喜欢使用
Null Object Pattern.
Avdi has a great post explaining this,但基本的想法是你有一个小类可以代表一个对象并合理地响应你可能传递原始对象的消息.我发现这些不仅对于避免NoMethodErrors有用,而且对于设置默认值/好消息也很有用.
例如,你可以这样做:
class NilUser def email "(no email address)" end end u = User.find(1) || NilUser.new u.email.upcase.last # => No errors!