コード日進月歩

しんくうの技術的な小話、メモ、つれづれ、など

Railsで with_indifferent_access を使うときは一呼吸おいて考えて欲しい

ただのコラム

(この話を題材にする)環境

$ bin/rails -v
Rails 5.2.2

with_indifferent_accessというメソッド

Hashの拡張機能としてAvtiveSupportが用意しているメソッド

rails/hash_with_indifferent_access.rb at master · rails/rails · GitHub

Hashのキー値をsymbolでも文字列でも取得可能にするもの。

hash = { a: "A", "b" => "B" , c: "C"}
convert_hash = hash.with_indifferent_access

# symbolで設定したものでも、文字列でも取得ができる
pp convert_hash["a"]
"A" 
pp convert_hash[:b]
"B"

従来使う際に考えてほしいこと

with_indifferent_access を施されたハッシュを利用する際に悩ましいポイント

このメソッドを通したほうが、 convert_hash["a"] でも convert_hash[:a] でも 取れるので一見便利だが普通のコードを書く場合は悩ましい部分ができる。

  1. このハッシュに内容をセットする側はsymbolで設定すべきか、文字列で設定すべきか悩んでしまう。
  2. 取り出す際もsymbolと文字列でどっちつかずになる可能性があり、取り出し記述の一貫性が失われる。

ただこの2つの観点はスコープ内でどっちの形式かに寄せてしまえばいいので deep_symbolize_keys もしくは deep_stringify_keys を使ってどちらかに全て変えてしまえば憂いはなくなる。

戻り値として with_indifferent_access のハッシュを使うケースに関して

ではこの with_indifferent_access を使うケースは何があるかと考えると思い浮かぶのは「メソッドの戻り値などでシンボルでも文字列でも扱えるように with_indifferent_access を施す」というケースが考えられる。

ただその場合はメソッドの作り手側がある程度どう使われて欲しいかが決めたほうが利用者側も悩まなくて済むのでそちらのほうが先程触れた利用側の憂いも減る。

いまだと deep_****_key でどちらかに寄せてあげればよさそう

こう考えていくと with_indifferent_access が強く切望されるケースは少なめなため、deep_****_key で揃えるほうが処理実態もその変換後の受け取る側もシンプルに考えることができるため、「その with_indifferent_access はなんでしたいのか」を考えたほうが良さそう。

参考サイト