简化Rails中的多个nil检查

问题描述 投票:2回答:10

我应该怎么写:

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

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

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

谢谢。

ruby-on-rails ruby syntax
10个回答
4
投票

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


0
投票

所有这些答案都很旧,所以我认为我应该分享更多现代选择。

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

@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)

如果子代,孙代或属性不存在,则以上两种都将正常返回nil


3
投票

您可以使用Object#andand

使用它,您的代码将如下所示:

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

3
投票

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

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

2
投票

为了娱乐,您可以使用折叠:

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

但是使用andand可能更好,或者使用ick,我非常喜欢它,并且具有类似trymaybe的方法。


0
投票

如果要检查的属性始终相同,请在@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检查就可以了


0
投票

您只想捕捉到例外:

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

0
投票

我想您可以使用delegate方法来执行此操作,因此您将得到类似的结果

@parent.child_grand_child_attribute.present?

0
投票

您好,您可以在此处使用带有救援选项的标志变量

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

if flag
do_something
end

0
投票

您可以这样做:

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

© www.soinside.com 2019 - 2024. All rights reserved.