ActiveRecord::QueryMethods
are methods provided by Rails to build
and execute database queries.
The select
method allows us to select specific fields from the database.
The reselect
method in ActiveRecord allows us to change the previously set select
statement.
Under the hood, reselect
is short-hand for unscope(:select).select(fields)
. Basically we’re unscoping the entire select statement.
User.select(:email).reselect(:first_name)
SELECT "users"."first_name" FROM "users"
Before
Before 7.1, we were able to reselect specific fields with column names as an array of strings or symbols, or we can provide raw SQL.
Client.select(:name, :phone).reselect(:name, :email)
# => output
SELECT "clients"."name", "clients"."email" FROM "clients"
Client.select("name", "phone").reselect("name", "email")
# => output
SELECT "clients"."name", "clients"."email" FROM "clients"
Client.select("name, phone").reselect("name, email")
# => output
SELECT name, email FROM "clients"
But to select the columns from an associated model, we only have the option to provide raw SQL.
Client
.joins(:projects)
.select(:name, :phone, "projects.billable")
.reselect(:name, :email, "projects.billable")
# => output
SELECT "clients"."name", "clients"."email", "projects"."billable"
FROM "clients"
INNER JOIN "projects" ON "projects"."client_id" = "clients"."id"
Client
.joins(:projects)
.select("clients.name, clients.phone, projects.billable")
.reselect("clients.name, clients.email, projects.billable")
# => output
SELECT clients.name, clients.email, projects.billable
FROM "clients"
INNER JOIN "projects" ON "projects"."client_id" = "clients"."id"
Client
.joins(:projects)
.select("clients.name AS client_name, clients.phone AS client_phone, projects.billable AS project_billable")
.reselect("clients.name AS client_name, clients.email AS client_email, projects.billable AS project_billable")
# => output
SELECT clients.name AS client_name, clients.email AS client_email, projects.billable AS project_billable
FROM "clients"
INNER JOIN "projects" ON "projects"."client_id" = "clients"."id"
After
Rails 7.1 allows ActiveRecord::QueryMethods#reselect to accept hash of columns and aliases and no need to use the raw version of the query anymore.
Let’s take a look at the same code after the change.
Client
.joins(:projects)
.select(:name, :phone, "projects.billable")
.reselect(:name, :email, projects: [:billable])
# => output
SELECT "clients"."name", "clients"."email", "projects"."billable"
FROM "clients"
INNER JOIN "projects" ON "projects"."client_id" = "clients"."id"
Client
.joins(:projects)
.select("clients.name, clients.phone, projects.billable")
.reselect(clients: [:name, :email], projects: [:billable])
# => output
SELECT "clients"."name", "clients"."email", "projects"."billable"
FROM "clients"
INNER JOIN "projects" ON "projects"."client_id" = "clients"."id"
Client
.joins(:projects)
.select("clients.name AS client_name, clients.phone AS client_phone, projects.billable AS project_billable")
.reselect(
clients: {name: :client_name, email: :client_email},
projects: { billable: :project_billable}
)
# => output
SELECT "clients"."name" AS client_name, "clients"."email" AS client_email, "projects"."billable" AS project_billable
FROM "clients"
INNER JOIN "projects" ON "projects"."client_id" = "clients"."id"
In the same way, Rails 7.1 allows ActiveRecord::QueryMethods#select to accept hash