所以我想根据是否已经给出输入来有条件地分配变量。
例如
@name = params[:input]['name'] || "Name not yet given"
但是,如果尚未传递参数,则会出现错误
method [] does not exist for nil class
我有两个想法来解决这个问题。一个是将[]方法添加到nil类。类似的东西:
class NilClass
def []
self
end
end
我的另一个想法是使用if语句
if params[:input].nil?
@name = params[:input]['name']
else
@name = "Name not yet given"
end
然而,这些解决方案都不是很正确。
什么是" ruby方式"?
答案 0 :(得分:6)
一种方法是使用Hash#fetch
。
params[:input].to_h.fetch('name', "Name not yet given")
答案 1 :(得分:2)
@name = params[:input].nil? ? "Name not yet given" : params[:input]['name']
.nil?
。另请参阅我的递归解决方案:https://stackoverflow.com/a/24588976/445221
答案 2 :(得分:2)
您总是可以编写一些代码来使其他代码变甜。
class Hash
def deep_fetch(*path)
path.reduce(self) { |memo, elem| memo ? memo[elem] : nil }
end
end
params = { input: { name: 'sergio' } }
params.deep_fetch(:input, :name) # => "sergio"
params.deep_fetch(:omg, :lol, :wtf) # => nil
答案 3 :(得分:1)
我喜欢使用NullObjects,或者更具体地说,黑洞对象用于此类事情。 Avdi Grimm为这个名为naught的结构赋予了我们巨大的红宝石宝石。因此,对于您的情况,我将安装gem,然后从创建项目特定的Null对象开始:
# add this to a lib file such as `lib/null_object.rb`
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
然后,在需要的地方加入NullObject::Conversions
并自信地前往城镇!
# my_class.rb
require 'null_object.rb'
include NullObject::Conversions
Maybe(params[:input])["name"].to_s.presence || "Name not yet given"
# => "Name not yet given"
这种黑洞方法的好处在于,任何额外的链接都不需要额外的步骤。你可以简单地将方法链接在一起,只要你愿意(自信)假设结果很好。然后,最后将值转换为期望的类型,如果链中的某些内容在您预期之前返回nil,那么显式转换将为您提供该版本的基本版本。
Maybe(params[:thing1])[:thing2][:thing3].map(&:to_i).sum.to_i
# => 0
或者,如果您愿意,可以使用Actual
将黑洞对象转换回实际值:
Actual(Maybe(params[:input])["name"]) || "Name not yet given"
有关Null对象模式的更多信息,请查看Avdi Grimm's post on the subject。总而言之,这是获得信心并停止类型检查的好方法(记住,甚至像nil
一样检查.try()
是类型检查!)。鸭子打字应该让我们免于类型检查!
答案 4 :(得分:1)
据我了解,对于散列h
,您想知道是否
h
有一个键:input
,如果有的话h[:input]
是一个哈希,如果是的话h[:input]
有一个键"name"
如果对所有三个人都是“是”,请返回h[:input]["name"]
;否则返回"Name not yet given"
。
所以请写下来:
def get_name(h)
if (h[:input].is_a? Hash) && h[:input].key?("name")
h[:input]["name"]
else
"Name not yet given"
end
end
params = { hat: "cat" }
get_name(params)
#=> "Name not yet given"
params = { input: "cat" }
get_name(params)
#=> "Name not yet given"
params = { input: {} }
get_name(params)
#=> "Name not yet given"
params = { input: { "moniker"=>"Jake" } }
get_name(params)
#=> "Name not yet given"
params = { input: { "name"=>"cat" } }
get_name(params)
#=> "cat"
另一种方式:
def get_name(h)
begin
v = h[:input]["name"]
v ? v : "Name not yet given"
rescue NoMethodError
"Name not yet given"
end
end
答案 5 :(得分:1)
您可以使用Ruby 2.3.0中引入的Hash#dig。
@name = params.dig(:input, 'name') || "Name not yet given"
同样,如果你想在链接方法时优雅地处理nil返回,你可以使用Ruby 2.3.0中引入的safe navigation operator。
@name = object&.input&.name || "Name not yet given"
答案 6 :(得分:0)
尝试获取密钥:
params[:input].try(:fetch, 'name', "Name not yet given")
假设你很可能在轨道上,否则你可以连接fetchs:
params.fetch(:input, {}).fetch 'name', "Name not yet given"
定义这样的参数是一种常见的做法:
def input_params
params.fetch(:input, {})
end
这将问题减少到:
input_params[:name] || 'Whatever'