Rails 6 adds Relation#reselect


Rails 6 has added reselect to Relation. This allows us to change the previously added fields in select.

Before

Rails already has rewhere and reorder. on Active Record Relation. Using them we can override existing where or order clauses on a Relation.

Similarly if one had to select different fields per query, one would have to do that on a new scope of the Relation.

users_registered_this_week = Person.
where("created_at > ? ", Date.current.beginning_of_week)

users_registered_this_week.
select(:first_name, :last_name, :email)
# => [#<Person id: 1, 
# first_name: "David", 
# last_name: "", 
# email: "dhh@loundthinking.com">]

users_registered_this_week.select(:email)
# => [#<Person id: 1, 
# email: "dhh@loundthinking.com">]

Relation#reselect

In an existing application, we can’t always pass scope around. We may have scopes, that already consist of the select clause. reselect now allows us to override the existing select clause:

class Person < ApplicationRecord
  def users_registered_this_week
    Person.
    where("created_at > ? ", Date.current.beginning_of_week).
    select(:first_name, :last_name, :email)
  end
end

Person.users_registered_this_week
# => [#<Person id: 1, 
# first_name: "David", 
# last_name: "", 
# email: "dhh@loundthinking.com">]

Person.users_registered_this_week.reselect(:email)
# => [#<Person id: 1, email: "dhh@loundthinking.com">]

This is a short-hand for unscope(:select).select(fields). Reselect unscopes the entire select statement and replaces it with new select clause.

Changes in SQL

We can take a look at how the SQL changes with usage of reselect:

Person.
select(:first_name, :last_name, :email).first

# Generated  Query: 
# SELECT  "people"."first_name", 
# "people"."last_name", 
# "people"."email" FROM "people" 
# ORDER BY "people"."id" ASC LIMIT $1  [["LIMIT", 1]]

Person.
select(:first_name, :last_name, :email).
reselect(:email).first

# Generated  Query:
# SELECT  "people"."email" FROM "people" 
# ORDER BY "people"."id" ASC LIMIT $1  [["LIMIT", 1]]