优雅地处理嵌套哈希中的空白值

时间:2012-04-27 22:31:35

标签: ruby-on-rails ruby

我确信之前我已经看到了一个优雅的解决方案,但我找不到它:

我有一个rails控制器,可能或者可能没有以下哈希元素:

myhash[:parent_field]

在该父字段内,子元素也可以为空。我目前正在通过(非常难看的)方法检查它:

if (!myhash[:parent_field] || !myhash[:parent_field][:child_field] || myhash[:parent_field][:child_field].blank?)

哪个有效,但我认为 - 当然 - 必须有更优雅的方式。只是重申:

  • myhash [:parent_field]可能存在也可能不存在
  • 如果确实存在,myhash [:parent_field] [:child_field]可能存在也可能不存在
  • 如果存在,则可能是空白,也可能不是空白。

6 个答案:

答案 0 :(得分:9)

#fetch是你的朋友:

my_hash.fetch(:parent, {})[:child].blank?

答案 1 :(得分:3)

我会做什么只是使用局部变量来减轻负担:

unless (p=foo[:parent]) && (c=p[:child]) && !c.blank?
  # Stuff is borked!
end

但是,为了好玩,让我们探索替代方案......


如果您无法更改数据结构(顺便说一下,这不是数组),那么您可以将Ruby andand gem与Rails'try结合使用在可能是nil个对象的事物上调用方法的方法。


当您要求输入不存在的密钥时,您也可以将数据结构更改为返回空的自动生成哈希值的哈希值:

mine = Hash.new{ |h,k| Hash.new(&h.default_proc) }
mine[:root] = { dive:42 }
p mine[:root][:dive]        #=> 42
p mine[:ohno][:blah][:whee] #=> {}
p mine[:root][:blah][:whee] #=> undefined method `[]' for nil:NilClass (NoMethodError)

但是,您必须确保层次结构中的每个对象都是其中一个哈希值(我明确无法对:dive的内容执行此操作,从而导致错误)。


为了另类乐趣,您可以添加自己的魔术查找方法:

class Hash
  def divedive(*keys)
    obj = self
    keys.each do |key|
      return obj unless obj && obj.respond_to?(:[])
      obj = obj[key]
    end
    obj
  end
end

if myarray.divedive(:parent,:child).blank?
  # ...

答案 2 :(得分:1)

这是一个经常被问到的问题,应该作为

的副本关闭

该列表中的第一个作为另外两个的副本被关闭,但我相信我的答案比后两个更全面地解决了这个问题。

答案 3 :(得分:0)

这可能取决于您的实际需求,但是对此的OOP方法是将数组和散列转换为实际对象。每个对象都会管理它的关系(类似于ActiveRecord),并且知道如何让孩子和父母。

答案 4 :(得分:0)

由于nil.blank?true,您可以删除中间条件并简化为:

if !myarray[:parent_field] || myarray[:parent_field][:child_field].blank?

另外,调用哈希myarray有点误导。

答案 5 :(得分:-2)

怎么样

!(myarray[:parent_field][:child_field] rescue nil).blank?