.pick: the single-row shortcut of .pluck
Where this picks up
The lesson "SELECT & FROM in Rails", in Raw SQL: select & from, covered the basics. .select(:name, :email) returns model objects with only the chosen columns filled in, and an unselected column reads back nil, which looks the same as a database NULL. .pluck(:name) skips building models and returns a plain array. A table in that lesson showed when to use .pluck, .select or .exists?. ActiveRecord querying: order/limit used .pluck constantly to print results without noise. This course goes further: .pick, the query-count difference between .pluck and .map(&:attr), .pluck across a join, distinct.pluck, and a trap specific to this app's Translatable concern.
The question .pick answers: one value, not a list
"What's the slug of the lowest-position course?" needs one string, not an array. .pluck always returns an array, even when only one row matters:
Catalog::Course.order(:position).pluck(:slug).first
# => "computer-architecture"
That works, but it fetches the slug of every matching course and then throws away all but the first in Ruby. .pick does the same job without the waste:
Catalog::Course.order(:position).pick(:slug)
# => "computer-architecture"
.pick runs LIMIT 1, .pluck.first doesn't
Here is the SQL each one sends, against this app's Catalog::Course table:
Course.order(:position).pick(:slug)
SELECT "courses"."slug" FROM "courses" ORDER BY "courses"."position" ASC LIMIT 1
Course.order(:position).pluck(:slug).first
SELECT "courses"."slug" FROM "courses" ORDER BY "courses"."position" ASC
.pick puts LIMIT 1 in the SQL, so the database stops after the first row. .pluck(:slug).first has no LIMIT. It pulls the slug of every course (a few hundred in this catalog) across the wire, builds an array that size in Ruby, and only then calls .first to keep one. On a small table you won't notice; on a large one, .pick is the one that scales.
.pick is built on .pluck
The Rails log labels a .pick call Course Pluck, not Course Pick. That isn't a display bug. Internally, .pick is .limit(1).pluck(*columns).first, the same mechanism this lesson just described by hand. That explains the label, and it means .pick inherits what .pluck does: no model objects, raw values back, and several columns supported the same way.
Several columns work too
Catalog::Course.order(:position).pick(:slug, :level)
# => ["computer-architecture", "intern"]
This is .pluck's multi-column shape (an array, not a hash) for the one row .pick stops at. It's the same array-of-values-per-row rule that "SELECT & FROM in Rails" showed for .pluck(:name, :email), cut down to a single row.
Key takeaways
- "SELECT & FROM in Rails" covered the
niltrap of.selectand the plain-array return of.pluck. This course goes on to.pick, query counts, joins and aTranslatabletrap. .pick(:column)returns a single value for one row, not an array..pluck(:column).firstimitates that by discarding everything after the first element..pickaddsLIMIT 1to the SQL, so the database stops after one row..pluck(:column).firsthas noLIMITand fetches every matching row's column before Ruby keeps the first..pickis.limit(1).pluck(*columns).firstinside, which is why the Rails log labels it "Pluck". It keeps the behavior of.pluck: no model objects, and an array for several columns.
Keep going with lesson 2
.pluck vs .map(&:attr): what costs a query
.pluck narrows the SELECT on unloaded relations, reads memory on loaded ones, and always queries for SQL expressions.
A free account also gives you the quizzes, your progress and notes, and the discussion.