TL;DR
-
ActiveRecord
でFIELD
関数を使っているときに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::IrreversibleOrderError
を throw
します。ちなみに、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_specified
gemを使って回避しました。
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
できるクエリを発行することができるので、 例外が発生しなくなりました。