.pick: o atalho de uma linha só do .pluck
De onde isto continua
A aula "SELECT & FROM no Rails", de SQL puro: SELECT e FROM, tratou do básico. .select(:name, :email) devolve objetos de model só com as colunas escolhidas preenchidas, e uma coluna não selecionada volta como nil, igual a um NULL do banco. .pluck(:name) pula a criação de models e devolve um array simples. Uma tabela naquela aula mostrou quando usar .pluck, .select ou .exists?. Querying ActiveRecord: order usou .pluck o tempo todo para imprimir resultados sem ruído. Este curso vai além: .pick, a diferença no número de consultas entre .pluck e .map(&:attr), .pluck através de um join, distinct.pluck e uma armadilha própria do concern Translatable deste app.
A pergunta que .pick responde: um valor, não uma lista
"Qual é o slug do curso de menor position?" precisa de uma string, não de um array. .pluck sempre devolve um array, mesmo quando só uma linha importa:
Catalog::Course.order(:position).pluck(:slug).first
# => "computer-architecture"
Funciona, mas busca o slug de todo curso que bate e depois joga fora tudo menos o primeiro, no Ruby. .pick faz o mesmo trabalho sem desperdício:
Catalog::Course.order(:position).pick(:slug)
# => "computer-architecture"
.pick roda LIMIT 1, .pluck.first não
Este é o SQL que cada um manda, na tabela Catalog::Course deste app:
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 põe LIMIT 1 no SQL, então o banco para depois da primeira linha. .pluck(:slug).first não tem LIMIT. Ele traz o slug de todo curso (algumas centenas neste catálogo) pela rede, monta um array desse tamanho no Ruby e só então chama .first para ficar com um. Numa tabela pequena você não percebe; numa grande, .pick é o que escala.
.pick é construído sobre .pluck
O log do Rails rotula uma chamada .pick como Course Pluck, não Course Pick. Não é erro de exibição. Por dentro, .pick é .limit(1).pluck(*columns).first, o mesmo mecanismo que esta aula descreveu à mão. Isso explica o rótulo, e significa que .pick herda o que .pluck faz: sem objetos de model, valores crus de volta e várias colunas aceitas do mesmo jeito.
Várias colunas também funcionam
Catalog::Course.order(:position).pick(:slug, :level)
# => ["computer-architecture", "intern"]
É o formato de várias colunas do .pluck (um array, não um hash) para a única linha em que .pick para. É a mesma regra de um array de valores por linha que "SELECT & FROM no Rails" mostrou para .pluck(:name, :email), reduzida a uma linha só.
Pontos-chave
- "SELECT & FROM no Rails" tratou da armadilha do
nilem.selecte do array simples de.pluck. Este curso segue para.pick, número de consultas, joins e uma armadilha doTranslatable. .pick(:column)devolve um único valor de uma linha, não um array..pluck(:column).firstimita isso descartando tudo depois do primeiro elemento..pickacrescentaLIMIT 1ao SQL, e o banco para depois de uma linha..pluck(:column).firstnão temLIMITe busca a coluna de toda linha que bate antes de o Ruby ficar com a primeira..pické.limit(1).pluck(*columns).firstpor dentro, por isso o log do Rails o rotula como "Pluck". Ele mantém o comportamento de.pluck: sem objetos de model, e um array para várias colunas.
Continue com a aula 2
.pluck vs .map(&:attr): o que custa uma query
.pluck estreita o SELECT em relations não carregadas, lê da memória nas carregadas e sempre consulta para expressões SQL.
Com uma conta grátis você também tem os quizzes, seu progresso e suas anotações, e a discussão.