如何更简洁地写这个?

时间:2014-08-24 12:28:36

标签: ruby-on-rails ruby

RoR中是否有一个允许我写这个的结构:

@budget_project_amounts.detect {|attributes| attributes['id'] == 659 }.attributes['amount'] if !@budget_project_amounts.detect {|attributes| attributes['id'] == 659 }.nil?

更简洁?不使用变量......

编辑:此部分

@budget_project_amounts.detect {|attributes| attributes['id'] == 659 }

无关紧要。它可能是任何东西。我有时会遇到类似这样的情况,我首先需要检查某些东西是否为零,然后才能继续得到它下面的值(如果它不是零,我正在寻找一种方法来做到这一点,而不是完全重复第一部分。我希望这是有道理的。

4 个答案:

答案 0 :(得分:3)

避免使用变量......您可以首先尝试使用if消除try条件:

@budget_project_amount.detect {|attributes| attributes['id'] == 659 }
                      .try(attributes).try(:[], 'amount')

然而,仅仅因为代码较少,并没有真正使代码更好。原始方法和这种方法的问题在于,它们都依赖于类型检查(对于NilClass)来完成工作。类型检查是一种代码味道。

我喜欢使用Naught进行类型检查。使用正确的空对象设置,您可以改为:

Maybe(@budget_project_amount.detect {|attributes| attributes['id'] == 659 }).attributes[:amount].to_f

基本上,忘记类型检查,只做您想做的事情,并确保最终结果是您正在寻找的对象类型(使用.to_f.to_i或其他)。

为了使上面的例子起作用,我定义了我的空对象:

require 'naught'

NullObject = Naught.build do |config|
  config.define_explicit_conversions
  config.define_implicit_conversions
  config.black_hole

  if $DEBUG
    config.traceable
  else
    config.singleton
  end
end

这提供了显式转换(对于.to_f)并且是一个黑洞(允许在链中调用多个方法,无论该链中的nil出现在哪里)。

答案 1 :(得分:2)

例如,您可以尝试短路(提及您的示例):

(bp = @budget_project_amount.find { |b| b['id'] == 12 }) && bp['amount']

表达式的结果是 nil 或您要搜索的金额。不到这一点,我什么都想不到。

它被称为short-circuit,因为如果第一个表达式的计算结果为 false ,则不会计算第二个表达式,从而避免在nil对象上调用该方法。

答案 2 :(得分:0)

您可以使用简单的

@budget_project_amount.
  select{ |x| x[:id] == 1 && x[:amount].present?}.
  map{|x| x[:amount] }.
  first

它将返回第一个amountnil

PS我猜ids是独一无二的......

答案 3 :(得分:0)

您可以使用抽象map_detect

紧凑地编写它
require 'facets/enumerable/map_detect'
amount = amounts.map_detect { |attrs| attrs['amount'] if attrs['id'] == 659 }