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]]