pluckメソッドがArrayのArrayではなくHashのArrayを返せるようにする
通好みのメソッドpluck Railsでアプリケーションを組むと、ActiveRecordのインスタンス生成コストが勿体ないな、と感じることが多いと思います。 そんな時の強い味方がpluckメソッドで、愛用される方も多いと思います。 Rails4からは複数のカラムも指定できて、使い勝手が向上しました。 複数カラムを指定すると、値がArrayのArrayで返って来ます。 例を示すと、例えばこんなデータがあるとすると employees id name created_at 1 Taro 2014-08-01 01:00:05 2 ...
通好みのメソッドpluck
Railsでアプリケーションを組むと、ActiveRecordのインスタンス生成コストが勿体ないな、と感じることが多いと思います。
そんな時の強い味方がpluckメソッドで、愛用される方も多いと思います。
Rails4からは複数のカラムも指定できて、使い勝手が向上しました。 複数カラムを指定すると、値がArrayのArrayで返って来ます。
例を示すと、例えばこんなデータがあるとすると
- employees
id | name | created_at |
---|---|---|
1 | Taro | 2014-08-01 01:00:05 |
2 | Jiro | 2014-08-01 02:00:06 |
3 | Saburo | 2014-08-01 03:00:07 |
Emplyee.pluck :id, :name => [[1, "Taro"], [2, "Jiro"], [3, "Saburo"]]
のように返ります。 これはこれで良いのですが、この結果をJSONで返したい時等は、できればHashのArray、つまり
Emplyee.hash_pluck :id, :name => [{:id=>1, :name=>"Taro"}, {:id=>2, :name=>"Jiro"}, {:id=>3, :name=>"Saburo"}]
のように返って欲しいです。 これを実現できるように、pluckメソッドに手を入れました。
ついでに、tableの物理column名と論理column名が異なることもあるだろうと、key名も指定できるようにしています。
前提条件
Rails4.1で動作を確認しました。
できあがったものがこちら
コードの細かい説明は省きます。短時間で書いた、と言い訳を先にしておきます。
module ActiveRecord::Calculations def pluck_with_keys *column_names unless (options = column_names.pop).is_a? Hash return pluck_without_keys *(column_names << options) end _pluck = pluck_without_keys *column_names case keys = options[:keys] when TrueClass _pluck.map{|obj| Hash[*column_names.zip(obj).flatten]} when Array _pluck.map{|obj| Hash[*keys.zip(obj).flatten]} else _pluck end end alias_method_chain :pluck, :keys end
これをRAILS_ROOT/lib/extensions/calculations.rb等に保存して、RAILS_ROOT/libをautoload_pathに追加した上でinitializer辺りでこのファイルをrequireします。
使ってみる
既存のシステムにも適用し易いように、元のpluckメソッドの挙動になるべく影響無いようにしています。
元々pluckは可変長引数を取りますが、最後の引数がオリジナルのpluckが取らないHashが来たら動きが変わります。
最後の引数にkeys: trueとすると、指定したcolumn名をkeyにしてHashが帰り、keys: [:employee_id, :employee_name]のようにkey名の配列を渡すと、そのように良い感じにしてくれます。
実際の動作はこのような感じです。
Employee.pluck :id, :name => [[1, "Taro"], [2, "Jiro"], [3, "Saburo"]] Employee.pluck :id, :name, keys: true => [{:id=>1, :name=>"Taro"}, {:id=>2, :name=>"Jiro"}, {:id=>3, :name=>"Saburo"}] Employee.pluck :id, :name, keys: [:employee_id, :employee_name] => [{:employee_id =>1, :employee_name=>"Taro"}, {:employee_id =>2, :employee_name=>"Jiro"}, {:employee_id =>3, :employee_name=>"Saburo"}]
key名が足りないと、あるものしか返しません。
Employee.pluck :id, :name, keys: [:employee_id] => [{:employee_id =>1}, {:employee_id =>2}, {:employee_id =>3}]
狙った通りに出来ました。
gemにしようかな。