Is there a clean way to avoid calling a method on

2020-01-24 09:41发布

I'm interested in getting the nested 'name' parameter of a params hash. Calling something like

params[:subject][:name]

throws an error when params[:subject] is empty. To avoid this error I usually write something like this:

if params[:subject] && params[:subject][:name]

Is there a cleaner way to implement this?

12条回答
时光不老,我们不散
2楼-- · 2020-01-24 10:09

Not really. You can try fetch or try (from ActiveSupport) but it's not much cleaner than what you already have.

More info here:

UPDATE: Forgot about andand:

andand lets you do:

params[:user].andand[:name] # nil guard is built-in

Similarly, you can use maybe from the Ick library per the answer above.

查看更多
劳资没心,怎么记你
3楼-- · 2020-01-24 10:11

When I have same problem in coding, I sometimes use `rescue'.

name = params[:subject][:name] rescue ""
# => ""

This is not good manners, but I think it is simple way.

EDIT: I don't use this way often anymore. I recommend try or fetch.

查看更多
家丑人穷心不美
4楼-- · 2020-01-24 10:12

I wrote Dottie for just this use case — reaching deep into a hash without first knowing whether the entire expected tree exists. The syntax is more succinct than using try (Rails) or maybe (Ick). For example:

# 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

Check out the docs if you want to see more: https://github.com/nickpearson/dottie

查看更多
Root(大扎)
5楼-- · 2020-01-24 10:14

Check Ick's maybe. You don't need to significantly refactor your code, just intersperse maybe proxies when necessary:

params[:subject].maybe[:name]

The same author (raganwald) also wrote andand, with the same idea.

查看更多
叼着烟拽天下
6楼-- · 2020-01-24 10:15

You can avoid the double hash access with an inline assignment:

my_param = subj_params = params[:subject] && subj_params[:name]
查看更多
够拽才男人
7楼-- · 2020-01-24 10:21

I cross posted this from my answer over here:

How to check if params[:some][:field] is nil?

I have been looking for a better solution too.

So I figured let's use try a different way to test for a nested key being set:

params[:some].try(:has_key?, :field)

It's not bad. You get nil vs. false if it's not set. You also get true if the param is set to nil.

查看更多
登录 后发表回答