简化Rails中的多个nil检查



我该怎么写:

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

无需繁琐的nil检查以避免异常:

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# and

有了它,你的代码看起来像这样:
if @parent.andand.child.andand.grandchild.andand.attribute

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

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

为了好玩,您可以使用fold:

[: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?不只是为nil,它也检查空白值,''。如果是nil检查,可以直接输入@parent.grandchild.attribute

您可以捕获异常:

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

这些答案都是旧的,所以我想我应该分享更多的现代选项。

如果您正在获取可能不存在的关联:

@parent&.child&.grand_child&.attribute

:

hash = {
 parent_key: {
   some_other_key: 'a value of some sort'
 },
 different_parent_key: {
   child_key: {
     grand_child: {
       attribute: 'thing'
     }
   }
 }
}
hash.dig(:parent_key, :child_key, :grandchild_key)

如果child、孙子或attribute不存在,这两种方法都会优雅地返回nil

最新更新