LoginSignup
57
56

More than 5 years have passed since last update.

pluckメソッドがArrayのArrayではなくHashのArrayを返せるようにする

Last updated at Posted at 2014-08-01

通好みのメソッド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にしようかな。

57
56
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
57
56