简化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
你可以使用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 ,我喜欢很多,并有像try
和maybe
方法。
如果要检查的属性始终相同,请在@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