2011-03-25 67 views
33

我有興趣獲取params散列的嵌套'name'參數。調用類似有沒有一種乾淨的方法來避免在嵌套參數散列中調用nil方法?

params[:subject][:name] 

params [:subject]爲空時會引發錯誤。爲了避免這種錯誤我平時寫的是這樣的:

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

有沒有實現這一個更清潔的方式?

+2

前幾天同樣的問題做:) http://stackoverflow.com/questions/5393974/ruby-nils-in-an-if-statement/5394240#5394240 – fl00r 2011-03-25 10:56:38

回答

19

檢查Ick也許。你並不需要顯著重構你的代碼,只是點綴也許代理必要時:

params[:subject].maybe[:name] 

同一作者(raganwald)也寫andand,用同樣的想法。

+1

伊克很迷人。 – 2011-03-25 08:08:14

+0

有趣的是,我之前沒有聽說過伊克。 – bowsersenior 2011-03-25 16:24:48

+0

現在,紅寶石已經消失,上面的鏈接到Ick的可能插件被打破。新的寶石網站rubygems.org有一個叫做也許在這裏的寶石:https://rubygems.org/gems/maybe。這與紅寶石僞造者Ick的相同嗎? – 2014-06-20 17:30:08

17
  1. 您可以使用#try,但我不認爲這是更好的:

    params[:subject].try(:[], :name) 
    
  2. 或者使用#fetch使用默認參數:

    params.fetch(:subject, {}).fetch(:name, nil) 
    
  3. 或者你也可以設置#default=到新的空散列,但不要嘗試修改從此返回的值:

    params.default = {} 
    params[:subject][:name] 
    

    也打破了現有的所有簡單的測試,所以你不能寫:

    if params[:subject] 
    

    ,因爲它會返回空散,現在你必須#present?調用添加到每個測試。

    此外,當密鑰沒有值時,即使您期望字符串,也總是返回散列值。

但從我看到的,你嘗試提取嵌套參數,而不是分配給模型,並在那裏放置你的邏輯。如果你有Subject模型,然後簡單地分配:

@subject = Subject.new(params[:subject]) 

shuld提取您的所有參數用戶填寫表單。然後嘗試保存它們,以查看用戶是否傳遞了有效值。

如果你擔心訪問該用戶不應該設置字段,然後(與@subject.attributes = params[:subject]用於更新在我的例子中,)

6

params[:subject].try(:[], :name)添加attr_accessible白名單whoich應該被允許與質量分配字段集是乾淨方式

+0

但是它會拋出異常,如果你沒有主題散列中的':name'字段。你必須將缺省值添加到'#fetch'' – MBO 2011-03-25 08:05:39

+0

對不起,我的意思是'params [:subject] .try(:[],:name)'我同意你的觀點並不一定比基本的詳細方式更好。 – lebreeze 2011-03-25 08:13:31

+0

在一個railscasts中,我認爲Ryan在沒有:[]的情況下使用try(我從那以後就使用了這個)。這將使這個解決方案更緊湊;) – Pierre 2011-03-25 08:17:03

4

當我在編碼中遇到同樣的問題時,我有時會使用'rescue'。

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

這不是禮貌,但我認爲這是簡單的方法。

編輯:我不再經常使用這種方式。我推薦tryfetch

2

或者,加上[]即可。

class NilClass; def [](*); nil end end 
params[:subject][:name] 
+1

這太好了。我刪除了我的,因爲這個比我的好多了。而且,感謝您使用沒有名稱的splat運算符'*'。我不知道這一點,並從你那裏瞭解到。 – sawa 2011-11-03 07:30:37

+1

更多人對此有何評論?這對我來說似乎很棒! – 2015-03-13 06:17:32

0

我寫Dottie只是這種使用情況 - 達深成散列不知道第一次在整個預期樹是否存在。語法比使用try(Rails)或maybe(Ick)更簡潔。例如:

# in a Rails request, assuming `params` contains: 
{ 'person' => { 'email' => '[email protected]' } } # there is no 'subject' 

# standard hash access (symbols will work here 
# because params is a HashWithIndifferentAccess) 
params[:person][:email] # => '[email protected]' 
params[:subject][:name] # undefined method `[]' for nil:NilClass 

# with Dottie 
Dottie(params)['person.email'] # => '[email protected]' 
Dottie(params)['subject.name'] # => nil 

# with Dottie's optional class extensions loaded, this is even easier 
dp = params.dottie 
dp['person.email'] # => '[email protected]' 
dp['subject.name'] # => nil 
dp['some.other.deeply.nested.key'] # => nil 

退房的文檔,如果你想看到更多:https://github.com/nickpearson/dottie

0

我用:

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 
1
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 
1

我從交叉我的答案在這裏發佈這樣的:

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

我一直在尋找一個更好的解決方案了。

所以我想再拿try不同的方法來測試一個嵌套的關鍵字設定:

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

它不壞。如果未設置,則獲得nilfalse。如果參數設置爲nil,您還會得到true

0

可避免與內嵌分配的雙重散列訪問:

my_param = subj_params = params[:subject] && subj_params[:name] 
8

的Ruby 2.3.0使這很容易與#dig

h = {foo: {bar: {baz: 1}}} 

h.dig(:foo, :bar, :baz)   #=> 1 
h.dig(:foo, :zot, :baz)   #=> nil 
+1

如果'h'爲'nil','h.dig'將會失敗。考慮使用安全導航運算符,或者將'.dig'與'h&.dig(:foo,:bar,:baz)'或'h&.foo&.bar&.baz'結合使用。 – thisismydesign 2017-09-11 15:32:39

+0

我以前的評論中有關哈希的安全導航器操作符的語法不正確。正確的語法是:'h&。[](:foo)&。[](:bar)&。[](:baz)'。 – thisismydesign 2017-09-18 15:22:26

相關問題