Rails 7.1 Allows ActiveRecord reselect Query Method To Accept Hash

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

Need help on your Ruby on Rails or React project?

Join Our Newsletter