0

I have a list of Active-record objects with multiple columns including brands.

[#<UsedCar id: 861214,  city_id: 4, place_id: 1, description: "abc",brand: "Toyota">,#<UsedCar id: 861214,  city_id: 4, place_id: 1, description: "abc",brand: "Honda">,#<UsedCar id: 861214,  city_id: 4, place_id: 1, description: "abc",brand: "Jeep">,#<UsedCar id: 861214,  city_id: 4, place_id: 1, description: "abc",brand: "Opel">,]

And another array of just brands

brands = %w[Toyota, Nissan, Lexus, Kia, Mazda, Honda, BMW, Range Rover, Chevrolet, Mitsubishi]

I want to to order the objects list as per the brands array ordering but not find any way by using sort_by or sort or group_by

Haseeb Ahmad
  • 7,914
  • 12
  • 55
  • 133
  • 2
    The commas and spaces in your array declaration are going to cause issues [See Here](https://stackoverflow.com/a/1275147/1978251) for more info – engineersmnky Sep 18 '21 at 17:33

3 Answers3

2

I would really recommend that you consider ordering the records in the database instead. Databases are really good at sorting and you don't have to pull every record out of the table just to get it in order.

You can do this in SQL with:

ORDER BY 
    CASE WHEN brand = 'Toyota' THEN 0
         WHEN brand = 'Nissan' THEN 1
         ...
         ELSE 100 END

You can create SQL CASE statements programatically with Arel:

cars = Car.arel_table
kase = Arel::Nodes::Case.new(cars[:brand]).
          when('Toyota').then(0).
          when('Nissan').then(1).
          when('Lexus').then(2)
Car.order(kase)

I'm pretty confident you can handle turning this into a loop with Enumerable#each_with_index and Enumerable#inject.

max
  • 96,212
  • 14
  • 104
  • 165
2

In Rails 7, you can use ActiveRecord::QueryMethods#in_order_of to construct the order by statement suggested by @max. Feature PR: https://github.com/rails/rails/pull/42061/files

brands = %w[Toyota Nissan Lexus Kia Mazda Honda BMW Range Rover Chevrolet Mitsubishi]

UsedCar.in_order_of(:brand, brands)
# => UsedCar Load (0.7ms)  SELECT "used_cars".* FROM "used_cars" ORDER BY CASE "used_cars"."brand" WHEN 'Toyota' THEN 1 WHEN 'Nissan' THEN 2 WHEN 'Lexus' THEN 3 WHEN 'Kia' THEN 4 WHEN 'Mazda' THEN 5 WHEN 'Honda' THEN 6 WHEN 'BMW' THEN 7 WHEN 'Range' THEN 8 WHEN 'Rover' THEN 9 WHEN 'Chevrolet' THEN 10 WHEN 'Mitsubishi' THEN 11 ELSE 12 END ASC

Also, if you have an array of UsedCar objects then also Rails 7 got you covered, as it also added Enumerable#in_order_of.

used_cars = [#<UsedCar id: 861214, city_id: 4, place_id: 1, description: "abc", brand: "Toyota">, #<UsedCar id: 861214, city_id: 4, place_id: 1, description: "abc", brand: "Honda">, #<UsedCar id: 861214, city_id: 4, place_id: 1, description: "abc", brand: "Jeep">, #<UsedCar id: 861214,  city_id: 4, place_id: 1, description: "abc", brand: "Opel">]

used_cars.in_order_of(:brand, brands)

the_spectator
  • 1,345
  • 11
  • 26
  • Nice - it looks very doable to backport this as well as all the Arel methods are available in Rails 6. – max Sep 20 '21 at 06:12
1

There is a already a pull request for Rails 7 to provide such feature

Based on that you can do

used_cars.index_by(&:brand).values_at(*brands).compact
Denny Mueller
  • 3,505
  • 5
  • 36
  • 67