This blog is part of our Rails 7 series.
Rails 7 introduces ActiveRecord::QueryMethods#in_order_of to fetch active record collection in a specific order based on the given attribute values.
We can see the similar method available for Enumerable#in_order_of to constrain records in a specific order from an enumerable collection by using key-series pair. You can find more details here in our blog regarding Enumerable#in_order_of method.
The newly introduced method is highly helpful to build queries by which we can specify an explicit order that we would like to get the collection as result. Otherwise we will have to make custom CASE statements to specify the order in raw SQL statement format.
1# Fetch Post records in order of [3, 5, 1] 2SELECT "posts".* FROM "posts" ORDER BY CASE "posts"."id" WHEN 3 THEN 1 WHEN 5 THEN 2 WHEN 1 THEN 3 ELSE 4 END ASC
Before
Suppose we have a Course model with status column having possible values like enrolled, started & completed. If we want to fetch all course records as a collection with status values in order of started, enrolled & completed, then the only option here is to build the CASE statement as raw SQL. Otherwise we will have to make iterations over the returned result to modify in the specific order we wish to get back.
1Course.order( 2 Arel.sql( 3 %q( 4 case status 5 when 'started' then 1 6 when 'enrolled' then 2 7 when 'completed' then 3 8 else 4 end 9 ) 10 ) 11)
Rails 7 onwards
The ActiveRecord::QueryMethods#in_order_of method will prepare either CASE statement or will make use of built-in function (Eg: FIELD in MySQL) based on the adapter to perform the specified order.
1Course.in_order_of(:status, %w(started enrolled completed))
The returned result here is an ActiveRecord::Relation object unlike the result for Enumerable#in_order_of where it is an array. Hence we can chain other scopes or query methods with the result while using ActiveRecord::QueryMethods#in_order_of method.
1Course.in_order_of(:status, %w(started enrolled completed)).order(:created_at: :desc).pluck(:name)
Please check out this pull request for more details.