0
Help us understand the problem. What are the problem?

posted at

updated at

Organization

Rails6でorder(:id)ではなく任意のID順で並び替えたい

駆け出しにもわかる簡単な並び替え

はじめまして、1年を経過した駆け出しRailsエンジニアです。
Model.where() で取得したリレーションを任意のID順で並び替えたいということがありました。
この記事はRails6向けとなっており、Rails7の方は最後の項目だけ読んで頂ければOKです:ok_hand:

それでは早速、下記のような animals テーブルを例として進めて行きます。

ID 名前(必要な情報) 年齢(不要な情報)
1 taro 2
2 hanako 7
3 jiro 4

まずはID順に並べる場合

animal_ids = [1, 3, 2]
Animal.where(id: animal_ids).order(:id).pluck(:name)
# SELECT "animals"."name" FROM "animals" WHERE "animals"."id" IN ($1, $2, $3) ORDER BY "animals"."id" ASC 
# => ["taro", "hanako", "jiro"]

何も気にすることはありませんね。
それでは本題へ:thumbsup:

指定したID順に並べたい

MySQLの場合FIELD が使えるそうです。

ORDER BY FIELD( id, '1', '3', '2');

私の環境はPostgreSQLの為、上記は見なかったことにします:innocent:

PostgreSQLの場合CASE でやるようです。

CASE id WHEN '1' THEN 0 WHEN '3' THEN 1 WHEN '2' THEN 2 END

というのがSQLでの並び替え方法のようです。
Arelを使用してSQLを書けばできるそうですが、、、 駆け出しには難しい :rolling_eyes:

sort_by を使った並び替え

今回はもっと簡単にRailsで sort_by を使用して並び替えることにします。

animal_ids = [1, 3, 2]
Animal.where(id: animal_ids).sort_by { |animal| animal_ids.index(animal.id) }.pluck(:name)
# SELECT "animals".* FROM "animals" WHERE "animals"."id" IN ($1, $2, $3)
# => ["taro", "jiro", "hanako"]

SQLで取得したものをRailsで並び替えていますが、多くの場合はこれで十分ではないでしょうか:zipper_mouth:
違いはSQL上で並び替えていないという点と ActiveRecord_Relation から Array に変わっている点です。

少し気になるのは SELECT "animals".* となっており pluck(:name) が効かず、全ての値を取得しています。
これは必要な値(name)とIDをSELECTしてあげましょう!

Animal.where(id: animal_ids).select(:id, :name).sort_by { |animal| animal_ids.index(animal.id) }.pluck(:name)
# SELECT "animals"."id", "animals"."name" FROM "animals" WHERE "animals"."id" IN ($1, $2, $3)
# => ["taro", "jiro", "hanako"]

良さそうですね:clap:
抽象化したscopeを作っておいても色々使えるかもしれません。
任意のカラムを好きな順に並べ替えることができます。

# @return [Array]
# @example
#   ActiveRecord_Relation.in_order_of(:id, [1, 3, 2])
#   => [Model(id: 1), Model(id: 3), Model(id: 2)]
scope :in_order_of, -> (column, values) {  
  sort_by { |x| values.index(x[column]) }    
}  

ん、in_order_of って、なに?

Rails7になれば in_order_of が使えます

はい、色々頑張りましたが、Rails7の方はSQL上でできちゃいます:angel:

ということで、今回の内容はRails6の方でRails7に上げるまで用として検討して頂ければと思います。
最後まで読んで頂きありがとうございました。

Register as a new user and use Qiita more conveniently

  1. You can follow users and tags
  2. you can stock useful information
  3. You can make editorial suggestions for articles
What you can do with signing up
0
Help us understand the problem. What are the problem?