LoginSignup
9
3

More than 3 years have passed since last update.

Rails5でID順にorder byしたい時にActiveRecord::IrreversibleOrderErrorが発生することがある

Last updated at Posted at 2018-03-10

TL;DR

  • ActiveRecordFIELD関数を使っているときにreverseをすると、ActiveRecord::IrreversibleOrderErrorが発生します。
  • 今回は、 order_as_specified gemを使ってこの問題を回避しました。

GitHub - panorama-ed/order_as_specified: Add arbitrary ordering to ActiveRecord queries.

起こったこと

タイムラインとかフィードを持つコンテンツや、ランキングなどの順番を別のロジックで生成している場合などに、指定したID順でレコードを取得したいケースがあると思います。

MySQLであれば、 FIELD関数が使えますし、Rails5を使っていれば下記のように記述できます。
MySQL :: MySQL 5.6 リファレンスマニュアル :: 12.5 文字列関数

ids = something_ordered_ids
Content.order(['field(`contents`.`id`, ?)', ids])

これと併用して、 reverseを使ってしまうと、ActiveRecord::IrreversibleOrderErrorが発生します。

単純にreverse できないようなクエリを実行しようとすると、 ActiveRecord::IrreversibleOrderErrorthrow します。ちなみに、last などと併用しても内部的にはreverseを使っているので、この例外がthrowされます。
rails commit log流し読み(2016/01/28) - なるようになるブログ

上記コードで生成されるクエリは、下記のようになっているので単純にreverseができないようです。

SELECT `contents`.* FROM `contents` WHERE `contents`.`id` IN (9, 8, 3, 4, 2, 1) ORDER BY field(`contents`.`id`, 9,8,3,4,2,1)

どうしたか

order_as_specifiedgemを使って回避しました。

ruby - rails のwhere句の結果を指定の順番で取り出す方法は? - スタック・オーバーフロー
GitHub - panorama-ed/order_as_specified: Add arbitrary ordering to ActiveRecord queries.

order_as_specified gemを使うと、FIELD関数ではないアプローチでID順に並べようとします。

SELECT `contents`.* FROM `contents` ORDER BY `contents`.`id`=9 DESC, `contents`.`id`=8 DESC, `contents`.`id`=3 DESC, `contents`.`id`=4 DESC, `contents`.`id`=
2 DESC, `contents`.`id`=1 DESC 

このクエリであれば、単純にreverseできるクエリを発行することができるので、 例外が発生しなくなりました。

9
3
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
3