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 }
无关紧要。它可能是任何东西。我有时会遇到类似这样的情况,我首先需要检查某些东西是否为零,然后才能继续得到它下面的值(如果它不是零,我正在寻找一种方法来做到这一点,而不是完全重复第一部分。我希望这是有道理的。
答案 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
它将返回第一个amount
或nil
PS我猜ids是独一无二的......
答案 3 :(得分:0)
您可以使用抽象map_detect:
紧凑地编写它require 'facets/enumerable/map_detect'
amount = amounts.map_detect { |attrs| attrs['amount'] if attrs['id'] == 659 }