selectpluck は、データベース テーブル内の 1 つまたは複数の列から値をコレクションとして返す、2 つの異なる便利な方法です。 たとえば、データベースに questions テーブルがあるとします。 各questionは3つのフィールドを持っているかもしれません。 id, question_text, そして関連するテーブルの foreign_key です。 question_text 列のみから値を返すには、select または pluck を使用します。 この2つのメソッドの違いを調べ、最後にRailsアプリケーション内でのpluckのアプリケーションを紹介します。

Select

select は2つの独自の方法で動作します:

i.select はブロックを受け取り、Array#select と同様に動作します。

Model.all.select { |m| m.field == value }

これはスコープに対してデータベースから Ruby オブジェクトの配列を構築し、配列に変換して Array#select を使用してそれらを反復処理します。

select vs where

大きなデータセット (例) で select にブロックを渡すと where:

Model.where(field: value)

なぜなら、Model.all.select { |m| m.field == value }では、Railsはまずテーブルの行をすべてRubyオブジェクトに変換し、各Rubyオブジェクトに対して与えられたブロックを実行しますが、Model.where(field: value)はSQL文を生成して重い作業をSQLにオフロードし、この種のフィルタリングではRubyより速いからです。

Model.select(:field)
# =>

例えば、私のプロジェクトでは、

Question.select(:question_text)
# => #<ActiveRecord::Relation >

これにより、次の SQL が生成されます:

SELECT "questions"."question_text" FROM "questions"

この 2 番目の例では、selectメソッドは配列を返さないことに注意してください;それは ActiveRecord::Relation オブジェクトを返します。 その結果、他のActiveRecord::QueryMethodsをこれに連結することができます。 例えば、

Question.select(:question_text).limit(5)# => #<ActiveRecord::Relation >

これは次のSQLを生成します。

SELECT "questions"."question_text" FROM "questions" LIMIT ? ]

Pluck

Railsガイドより:

pluck はモデルの基本テーブルから単一または複数の列を照会するために使用することができます。 引数として列名のリストを受け取り、対応するデータ型を持つ指定された列の値の配列を返します。

ここで重要な点は、pluck は配列を返すということです。 selectのようにActiveRecord::Relationオブジェクトを返すわけではありません。 たとえば、

Question.pluck(:question_text)# => # this returns an array with all of the values from the question_text column from the questions table.

pluckActiveRecord オブジェクトを作成せずにデータベースへの問い合わせ結果を Ruby の配列に変換するので、select よりもパフォーマンスが高くなります。

Question.pluck(:question_text).limit(5)# => NoMethodError: undefined method `limit' for #<Array:0x007fc5c1dfb3b0>

しかし、pluckActiveRecord オブジェクトに対して動作するので、次のようにすると期待通りの結果を返します:

Question.limit(5).pluck(:question_text)#=> 

pluck は多次元配列を構築するために複数の引数を取ることができます:

Question.pluck(:question_text, :course_id)#=> , , ...]

Pluck はいつ使うのか?

pluck を使って ActiveRecord モデル オブジェクトをスコープし、どのモデル オブジェクトが別のテーブルの関連レコードを持っているかを判断することができます。 以下はその方法です。

まず、Model.where(field: value)の場合、valueは単一のオブジェクト(integerstringなど)か、オブジェクトのarrayであることを覚えておいてください。

したがって、以下は有効で、配列に含まれるidsを持つすべてのを返すことになります。

Appointment.where(id: )# => returns all appointments with ids that are included in the array

さて、pluck が配列を返すことは分かっているので、関連付けられたモデルでスコープしたい外部キーを含む配列を構築することができます。 例えば、どの appointmentscharges と関連しているかを判断したい場合、以下のように charges テーブルの appointment_id カラムから配列を作成できます:

Charge.pluck(:appointment_id)# => returns an array with all of the appointment_ids from the charges table, like: 

どの appointments が料金と関連しているかを判断するには、以下のように記述できます。

Appointment.where(id: Charge.pluck(:appointment_id))# this is the same as Appointment.where(id: )

これをAppointmentモデルのスコープに変換すると:

class Appointment < ActiveRecord::Base
has_many :charges scope :received_payment_info, -> {
where(id: Charge.pluck(:appointment_id)) }end

つまり、appointmentschargesと関連付けられているかを判断したい場合は、次のように記述します。

Appointment.received_payment_info#=> #<ActiveRecord::Relation 

と書くことができ、次のようなSQLクエリが生成されます:

SELECT "charges"."appointment_id" FROM "charges"SELECT "appointments".* FROM "appointments" WHERE ("appointments"."id" IN (35, 44, 82) OR "appointments"."id" IS NULL)

pluck によって、私たちは

  1. 関連データベース テーブルに効率的にクエリを実行して…
  2. 主テーブルからのオブジェクトのすべての foreign_key を含む関連テーブルから配列を生成し、
  3. その配列を使って主テーブルのオブジェクトと副テーブルの関連オブジェクトを判断する

これが役に立ったことを願っております。 摘出と選択を楽しんでください。

コメントを残す

メールアドレスが公開されることはありません。