💎

[Ruby on Rails](Tips)pluckメソッドはEnumerablesに対しても使える

2023/10/18に公開

初めましてRuonです。

最近railsでサーバーサイドを実装している際に気づいたpluckメソッドの使い方について軽く紹介します。

Ruby on Railsのpluckメソッドは、通常、ActiveRecordのクエリを最適化するために使われるものです。しかし、あまり知られていない事実として、pluckメソッドは、Rubyの基本的なEnumerables(例: 配列やハッシュ)に対しても使用することができるのです。私自身、pluckメソッドは基本的にActiveRecordで取得したレコードの特定のカラムの値を配列で返してくれるメソッドだと思っていましたので少し驚きました。それではこれについて詳しく説明していきます。

ActiveRecordでのpluck

まず、基本的な使い方を思い出してみましょう。pluckメソッドはActiveRecordモデルに対して、特定のカラムだけを返すときに非常に便利です。

emails = User.pluck(:email)

この再発行されるSQLは以下のようです

SELECT `users`.`email` FROM `users`

この例では、SQLのSELECT文を最適化し、データベースのusersテーブルからメールアドレスのカラムのみを取得します。
これは皆さんも馴染み深いでしょう。

Enumerableでのpluck

しかし、ある時点でオブジェクトの配列を持っており、それぞれのオブジェクトから特定の属性やメソッドの値を取得したい場合があります。そのような場合にもpluckを使用できます。

その前に

そもそもEnumerableとは?

Rubyの中で非常に重要な役割を果たすモジュールの一つが、Enumerableです。しかし、Enumerableとは何でしょうか

EnumerableはRubyの組み込みモジュールであり、繰り返しのためのメソッドを多数提供しています。これにより、配列やハッシュなどのコレクションオブジェクトを効率的に扱うことができるんですね
https://docs.ruby-lang.org/ja/latest/class/Enumerable.html

このモジュールのメソッドは全て each を用いて定義されているので、インクルードするクラスには each が定義されていなければなりません。

とあるので、このモジュールを活用するには、特定のオブジェクトがeachメソッドを定義している必要があります。つまり、eachメソッドが使えるようなArray, Hash, Range,などのクラスにおいて、Enumerableをincludeしているようですね。Enumerableモジュールはこのeachメソッドを基盤として、さまざまな便利な繰り返しのためのメソッドを提供しているようです。

代表的なEnumerableメソッド

map/collect: コレクションの各要素に対して処理を適用し、その結果を新しい配列として返す。
select/filter: 特定の条件に合致する要素だけを抽出する。
reject: 特定の条件に合致しない要素だけを抽出する。
reduce/inject: コレクションの要素を順番に処理し、累積結果を返す。
all?: 全ての要素が特定の条件を満たすかを確認する。
any?: 一つでも条件を満たす要素があるかを確認する。
... など

このEnumerableモジュールのおかげで我々は普段これらのメソッドを使えるようです。

しかし、先ほどのドキュメントの中身を確認してもpluckメソッドは見当たりません。pluckメソッドはActive Supportというgemによって提供されているrubyの拡張機能なんですね。RailsにはこのActive Supportが組み込まれているため普段の開発でこれを意識せずともpluckメソッドを使用することができます。https://guides.rubyonrails.org/active_support_core_extensions.html#:~:text=enumerable.rb.-,10.7 pluck,-The method pluck

pluckメソッドの使い方

さて、本題に入ります。以下のようなhashの配列に対してpluckメソッドを使用します。

people = [
  { :id => 1, :name => "Alice", :email => "alice@example.com" },
  { :id => 2, :name => "Bob", :email => "bob@example.com" },
  { :id => 3, :name => "Charlie", :email => "charlie@example.com" }
]

names = people.pluck(:name)
# => ["Alice", "Bob", "Charlie"]

このように、ActiveRecord以外にも単純な配列に対してもpluckメソッドを使用することができます。

どうでしょうか?普段お世話になっているpluckメソッドですが、db操作以外にもこんな単純な使い方があったんですね。また、個人的にはこの使い方はテストコードでのレスポンスのjsonに対して使えると思いました。

target_person_id = 1
assert_includes JSON.parse(@response.body)['people'].pluck('id'), target_person_id

みたいな感じですね!

まとめ

pluckメソッドは、データベースからの情報の取得を最適化するためだけでなく、Rubyの基本的なEnumerablesの操作にも役立ちます。この機能を活用して、コードの読みやすさや効率を向上させることができると思いました。また、EnumerableモジュールやActive Supportの知見も得ることができて個人的にとてもよかったです。また何か面白い気づきなどがあったら記事にしてみたいと思います。
最後まで読んでくださりありがとうございました。

Discussion