この記事で紹介すること
params
はHash
ではなくActionController::Parameters
のインスタンスのため、キーの型がString
かSymbol
かを区別することなく値を取ってくることができます。
開発環境
ruby2.5.1
rails5.2.1
paramsはキーがStringかSymbolかを区別しない
rubyでは、Hash
はキーの型を区別するため、以下のように動作します。
# rubyでは...
h = { :last_name => "佐藤", "first_name" => "太郎" }
# キーに指定した要素の型で値を取ってくることができる
h[:last_name] #=> "佐藤"
h["first_name"] #=> "太郎"
# 指定した要素とは違う型で値を取ってくることはできない
h["last_name"] #=> nil
h[:first_name] #=> nil
ところが、railsのparams
はActionController::Parameters
のインスタンスであり、Hash
の機能が拡張されているためキーの型に関係なく値を取ってくることができます。
# railsで受け取ったparams
params
=> <ActionController::Parameters {"last_name"=>"佐藤", "first_name"=>"太郎"}>
# paramsの見た目はHashだが、ActionController::Parametersのインスタンス
params.class
=> ActionController::Parameters
# キーの型に関係なく値を取ってくることができる!
params["last_name"] #=> "佐藤"
params["first_name"] #=> "太郎"
params[:last_name] #=> "佐藤"
params[:first_name] #=> "太郎"
追記 paramsの型をHashに変換するには?
以下、この記事を読んでいただいた経験豊富なエンジニアの方から教わった知見です。
マスアサインメントによる事故を防ぐためにRails4以降ではparamsを直接Hash
に変換することは出来なくなっています。
# 適当にparamsのようなインスタンスをつくる
pry(main)> params = ActionController::Parameters.new(:hoge => :huga, 'foo' => 'bar')
=> <ActionController::Parameters {"hoge"=>:huga, "foo"=>"bar"} permitted: false>
# 外部から入力できるparamsのマスアサインメントによる事故を防ぐために
# そのままではハッシュにならない(Rails4よりも前のバージョンではこれでも変換できた)
pry(main)> params.to_h
=> ActionController::UnfilteredParameters: unable to convert unpermitted parameters to hash
# 明示的に許可したものだけハッシュになる
pry(main)> params.permit(:hoge).to_h
=> Unpermitted parameter: :foo # :foo は許可されないため捨てられる
=> {"hoge"=>:huga} # :hogeは許可されるためハッシュ化する
pry(main)> params.permit(:hoge, :foo).to_h
=> {"hoge"=>:huga, "foo"=>"bar"} # 全てハッシュになる
# 危険なのを分かっていて、無理やりハッシュにしたい時
# やりかた1
pry(main)> params.to_unsafe_h
=> {"hoge"=>:huga, "foo"=>"bar"}
# やりかた2
pry(main)> params.permit!
=> <ActionController::Parameters {"hoge"=>:huga, "foo"=>"bar"} permitted: true>
pry(main)> params.to_h
=> {"hoge"=>:huga, "foo"=>"bar"}
参考サイト
・ActionController::Parametersの内部実装など
https://github.com/rails/rails/blob/master/actionpack/lib/action_controller/metal/strong_parameters.rb
https://github.com/rails/rails/blob/master/activesupport/lib/active_support/hash_with_indifferent_access.rb
・マスアサインメントについて
https://railstutorial.jp/chapters/sign_up?version=4.2#sec-strong_parameters
https://railsguides.jp/action_controller_overview.html#strong-parameters