有没有一个干净的方法,以避免调用一个嵌套的参数哈希零的方法?
我有兴趣获取params散列的嵌套的“名称”参数。 调用类似
params[:subject][:name]
当params [:subject]为空时抛出一个错误。 为了避免这个错误,我通常会写这样的东西:
if params[:subject] && params[:subject][:name]
有没有一个更清晰的方式来实现这一点?
检查伊克 也许 。 你不需要重构你的代码,只需要在必要时散布代理即可:
params[:subject].maybe[:name]
同一个作者( raganwald )也写了和有同样的想法。
-
你可以使用
#try
,但我不认为它好多了:params[:subject].try(:[], :name)
-
或者使用默认参数
#fetch
:params.fetch(:subject, {}).fetch(:name, nil)
-
或者,您可以将
#default=
设置为新的空散列,但不要尝试修改从此返回的值:params.default = {} params[:subject][:name]
它也打破了存在的所有简单testing,所以你不能写:
if params[:subject]
因为它会返回空的散列,现在你必须添加
#present?
呼吁每一个testing。当key没有值的时候,这总是返回散列值,即使你期望string。
但是从我所看到的,你尝试提取嵌套的参数,而不是分配给模型,并在那里放置你的逻辑。 如果您有Subject
模型,那么只需指定:
@subject = Subject.new(params[:subject])
shuld提取所有用户填写的参数表单。 然后尝试保存它们,以查看用户是否传递了有效值。
如果您担心访问用户不应该设置的字段,那么添加attr_accessible
白名单,以便允许用质量分配来设置的字段(在我的示例中,用@subject.attributes = params[:subject]
进行更新)
Ruby 2.3.0使用#dig很容易做到这一点
h = {foo: {bar: {baz: 1}}} h.dig(:foo, :bar, :baz) #=> 1 h.dig(:foo, :zot, :baz) #=> nil
params[:subject].try(:[], :name)
是最干净的方法
当我在编码方面有同样的问题时,我有时会使用“救援”。
name = params[:subject][:name] rescue "" # => ""
这不是礼貌,但我认为这是简单的方法。
编辑:我不经常使用这种方式了。 我build议try
或fetch
。
不是真的。 您可以尝试(从ActiveSupport) fetch
或try
,但它不是比你已经有的更干净。
更多信息:
- 嵌套散列定义?()
更新:忘记和和:
andand
让你做:
params[:user].andand[:name] # nil guard is built-in
同样,你可以使用上面的答案,从Ick库 。
或者,向其中添加[]
。
class NilClass; def [](*); nil end end params[:subject][:name]
class Hash def fetch2(*keys) keys.inject(self) do |hash, key| hash.fetch(key, Hash.new) end end end
例如
require 'minitest/autorun' describe Hash do it "#fetch2" do { yo: :lo }.fetch2(:yo).must_equal :lo { yo: { lo: :mo } }.fetch2(:yo, :lo).must_equal :mo end end
我交叉从这里回答这个:
如何检查params [:some] [:field]是否为零?
我一直在寻找更好的解决scheme。
所以我想我们使用try
一种不同的方式来testing被设置的嵌套键:
params[:some].try(:has_key?, :field)
不算太差。 如果没有设置,你会得到nil
与false
。 如果param被设置nil
你也会变成true
。
我为这个用例写了Dottie – 深入到一个散列,而不知道整个预期的树是否存在。 语法比使用try
(Rails)或者(Ick)更简洁。 例如:
# in a Rails request, assuming `params` contains: { 'person' => { 'email' => 'jon@example.com' } } # there is no 'subject' # standard hash access (symbols will work here # because params is a HashWithIndifferentAccess) params[:person][:email] # => 'jon@example.com' params[:subject][:name] # undefined method `[]' for nil:NilClass # with Dottie Dottie(params)['person.email'] # => 'jon@example.com' Dottie(params)['subject.name'] # => nil # with Dottie's optional class extensions loaded, this is even easier dp = params.dottie dp['person.email'] # => 'jon@example.com' dp['subject.name'] # => nil dp['some.other.deeply.nested.key'] # => nil
查看文档,如果你想看到更多: https : //github.com/nickpearson/dottie
我用了:
params = {:subject => {:name => "Jack", :actions => {:peaceful => "use internet"}}} def extract_params(params, param_chain) param_chain.inject(params){|r,e| r=((r.class.ancestors.include?(Hash)) ? r[e] : nil)} end extract_params(params, [:subject,:name]) extract_params(params, [:subject,:actions,:peaceful]) extract_params(params, [:subject,:actions,:foo,:bar,:baz,:qux])
得到:
=> "Jack" => "use internet" => nil
您可以通过内联分配避免双重哈希访问:
my_param = subj_params = params[:subject] && subj_params[:name]