3

Rails 7.1 allows ActiveRecord::QueryMethods#select & #reselect to receive ha...

 1 year ago
source link: https://blog.kiprosh.com/rails-7-1-allows-activerecord-querymethods-select-and-reselect-to-receive-hash-values/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

rails_7 Published on  9 November 2022 9 November 2022 • 2 min read

Rails 7.1 allows ActiveRecord::QueryMethods#select & #reselect to receive hash values

An ActiveRecord query by default uses the SELECT * operator to select all the fields from the result set. The ActiveRecord::QueryMethods#select method allows you to select a subset of fields from the result set.

Before Rails 7.1

ActiveRecord::QueryMethods#select and ActiveRecord::QueryMethods#reselect only accept strings, symbols, or raw SQL to define columns and aliases to select.

When querying a single model, we can provide column names as an array of strings or symbols, or we can provide raw SQL.

> Model.select(:field, :other_field)
> # OR
> Model.select('field', 'other_field')
> # OR
> Model.select('field, other_field')

But when you need to select the columns from an associated model, we only have the option to provide raw SQL.

> Model.joins(:sub_models).select('models.field AS models_field_alias, sub_models.field AS sub_models_field_alias')

Rails 7.1 onwards

Rails 7.1 adds the ability to pass a hash of columns and aliases to be selected with the ActiveRecord::QueryMethods#select and ActiveRecord::QueryMethods#reselect methods.

Model.select(:field, :other_field)
Model.select(field: :field_alias)
Model.select(table_name: [:field, :other_field])
Model.select(table_name: { field: :field_alias, other_field: :other_field_alias })

Examples

# Table name: customers
#
#  id               :integer
#  name             :string
#  email            :string
#  shipping_address :text
#  created_at       :datetime
#  updated_at       :datetime

class Customer < ApplicationRecord
  has_many :orders
end

# Table name: orders
#
#  id             :integer
#  date           :date
#  total          :decimal
#  customer_id    :integer
#  created_at     :datetime
#  updated_at     :datetime

class Order < ApplicationRecord
  belongs_to :customer
end
  • Without aliases

    Loading development environment (Rails 7.1.0.alpha)
    3.1.0 :001 > Customer.joins(:orders).select("customers.id, customers.name, orders.date, orders.total")
      Customer Load (0.2ms)  SELECT customers.id, customers.name, orders.date, orders.total FROM "customers" INNER JOIN "orders" ON "orders"."customer_id" = "customers"."id" /* loading for pp */ LIMIT ?  [["LIMIT", 11]]
    

    now written as ↓

    Loading development environment (Rails 7.1.0.alpha)
    3.1.0 :001 > Customer.joins(:orders).select(customers: [:id, :name], orders: [:date, :total])
      Customer Load (0.2ms)  SELECT "customers"."id", "customers"."name", "orders"."date", "orders"."total" FROM "customers" INNER JOIN "orders" ON "orders"."customer_id" = "customers"."id" /* loading for pp */ LIMIT ?  [["LIMIT", 11]]
    
  • With aliases

    Loading development environment (Rails 7.1.0.alpha)
    3.1.0 :001 > Customer.joins(:orders).select("customers.id, customers.name AS customer_name, orders.date AS order_date, orders.total AS order_total")
      Customer Load (0.2ms)  SELECT customers.id, customers.name AS customer_name, orders.date AS order_date, orders.total AS order_total FROM "customers" INNER JOIN "orders" ON "orders"."customer_id" = "customers"."id"
    

    now written as ↓

    Loading development environment (Rails 7.1.0.alpha)
    3.1.0 :001 > Customer.joins(:orders).select(customers: { id: :id, name: :customer_name }, orders: { date: :order_date, total: :order_total })
    Customer Load (2.0ms)  SELECT "customers"."id" AS id, "customers"."name" AS customer_name, "orders"."date" AS order_date, "orders"."total" AS order_total FROM "customers" INNER JOIN "orders" ON "orders"."customer_id" = "customers"."id"
    

The same applies for ActiveRecord::QueryMethods#reselect.

Note: If you want to use SQL functions in ActiveRecord::QueryMethods#select you still need to pass raw SQL. i.e.

Loading development environment (Rails 7.1.0.alpha)
3.1.0 :028 > Customer.joins(:orders).group('orders.customer_id').select("customers.id, COUNT(orders.id) AS order_count")
  Customer Load (1.2ms)  SELECT customers.id, COUNT(orders.id) AS order_count FROM "customers" INNER JOIN "orders" ON "orders"."customer_id" = "customers"."id" GROUP BY "orders"."customer_id"

References

Sampat Badhe

Sampat Badhe

I am a Rubyist and Node.js developer at Kiprosh.com. I enjoy building innovative applications and currently in love with TDD practice. I am practicing Agile and love to pair program.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK