Rails 的 HashWithIndifferentAccess
我們先從 rails 的 parameter 開始談
我們常會用 params[:id]
來撈資料,但是為何 params 會有像是Ruby hash 的操作呢?
>> params
=> <ActionController::Parameters {"controller"=>"brands", "action"=>"show", "id"=>"icook"} permitted: false>
>> params[:id]
=> "icook"
>> params.class
=> ActionController::Parameters
透過 params.class 我們知道可以去查 strong parameter 的 source code 來追根究底,發現一層層 require 最後會連到 HashWithIndifferentAccess
- rails api: Action Controller Parameters
- rails/actionpack/lib/action_controller/metal/strong_parameters.rb
- strong parameter 的 initialize
- rails/activesupport/lib/active_support/core_ext/hash/indifferent_access.rb
- rails/activesupport/lib/active_support/hash_with_indifferent_access.rb
HashWithIndifferentAccess
就如同他的命名所示,key 無論是用 symbol 或是 string 來撈,都是沒有差別的 ( indifferent )
>> params[:id]
=> "icook"
>> params['id']
=> "icook"
就像 ruby hash 的 slice, strong parameter 所實作的 slice 也是出自 HashWithIndifferentAccess
的 slice 。。
所以我們也可以像平常 ruby 用 slice 的寫法
>> params
=> <ActionController::Parameters {"controller"=>"brands", "action"=>"show", "id"=>"icook"} permitted: false>
>> params.slice(:controller, :id)
=> <ActionController::Parameters {"controller"=>"brands", "id"=>"icook"} permitted: false>
>> params.slice('controller', 'id')
=> <ActionController::Parameters {"controller"=>"brands", "id"=>"icook"} permitted: false>
最後讓我們回來看一下 HashWithIndifferentAccess
的 doc 或 initialize 的 source code 會發現
我們也可以傳一個普通的 ruby hash 給 HashWithIndifferentAccess.new
讓他轉生成強大的 HashWithIndifferentAccess
instance ,然後這個 instance 就不用煩惱 key 用 symbol 或 string 了
注意:
用 ActiveSupport::HashWithIndifferentAccess
生出的 hash 不適合與 Ruby 的 Hash
生出的 hash 混著用,容易有預料之外的問題,i.e:
regular = Hash.new
regular[:one] = 1
regular[:two] = 2regular # => {:one=>1, :two=>2}indifferent = HashWithIndifferentAccess.new
indifferent[:one] = "one"regular.merge(indifferent)
# => {:one=>1, :two=>2, "one"=>"one", "two"=>"two"}
ref:http://jocellyn.cz/2014/05/03/hash-with-indifferent-access.html
相關文章