简化Rails中的多个nil检查

我该怎么写:

if @parent.child.grand_child.attribute.present? do_something 

没有繁琐的零检查以避免exception:

 if @parent.child.present? && @parent.child.grandchild.present? && @parent.child.grandchild.attribute.present? 

谢谢。

Rails有object.try(:method)

 if @parent.try(:child).try(:grand_child).try(:attribute).present? do_something 

http://api.rubyonrails.org/classes/Object.html#method-i-try

你可以使用Object#和 。

有了它,你的代码看起来像这样:

 if @parent.andand.child.andand.grandchild.andand.attribute 

您可以通过将中间值分配给某个局部变量来略微减少它:

 if a = @parent.child and a = a.grandchild and a.attribute 

为了好玩,你可以使用折叠:

 [:child, :grandchild, :attribute].reduce(@parent){|mem,x| mem = mem.nil? ? mem : mem.send(x) } 

但使用andand可能更好,或ick ,我喜欢很多,并有像trymaybe方法。

如果要检查的属性始终相同,请在@parent中创建方法。

 def attribute_present? @parent.child.present? && @parent.child.grandchild.present? && @parent.child.grandchild.attribute.present? 

结束

或者,创建has_many :through关系,以便@parent可以到达grandchild以便您可以使用:

 @parent.grandchild.try(:attribute).try(:present?) 

注意: present? 不仅仅是为零,它还会检查空白值, '' 。 如果只是零检查,你可以做@parent.grandchild.attribute

你只能抓住exception:

 begin do something with parent.child.grand_child.attribute rescue NoMethodError => e do something else end 

我想你可以使用delegate方法来做到这一点,你会有类似的结果

 @parent.child_grand_child_attribute.present? 

嗨,您可以在这里使用带有救援选项的标志变量

 flag = @parent.child.grand_child.attribute.present? rescue false if flag do_something end 

你可以这样做:

 Optional = Struct.new(:value) do def and_then(&block) if value.nil? Optional.new(nil) else block.call(value) end end def method_missing(*args, &block) and_then do |value| Optional.new(value.public_send(*args, &block)) end end end 

您的支票将变为:

 if Optional.new(@parent).child.grand_child.attribute.present? do_something 

资料来源: http : //codon.com/refactoring-ruby-with-monads