RailsでActive Recordを利用して記事を取得した場合、where
に指定したIDなどの順番通りにデータを取得したいときはありますよね。
ただし、デフォルトではwhere
に入れる順番を調整したとしても、取得時にはソートされ直してしまいます。
例えば、下記のように複数のIDを指定したとします。
Model.where(id: [3,4,1,2])
その結果、取得されるデータはIDが若い順(1, 2, 3, 4)となってしまいます。
もちろんorder
を使ってうまく調整できればいいのですが、難しいときもあるはず。
小難しいことはせずwhere
に入れた順番でそのまま取得したいときは、ちょっと工夫が必要なのでその方法をまとめました。
実行環境:
Rails 6.1.4
Ruby 2.7.4
whereで指定した順番で取得する方法2つ
主な方法は下記の通り2つあります。
- FIELD関数を使う
- gem「order_as_specified」を使う
FIELD関数を使う
Model.where(id: ids).order(['field(id, ?)', ids])
Ruby v4.2.5以降から使えるようになったものです。
利用自体はシンプルで、MySQLでもPostgreSQLでも動作します。
ただし、私の場合は本番環境で一部うまく動作しなかったので、次に紹介するgemを使う方法を採用しました。
gem「order_as_specified」を使う
whereで指定した順でデータが取得できるようにしてくれる便利なgemが「order_as_specified」。
https://github.com/panorama-ed/order_as_specified
使い方も非常に簡単です。
1. gemを追加する
まずGemfileに以下のように記述します。
gem 'order_as_specified'
その後bundleでインストール。
$ bundle install
これでgem「order_as_specified」の追加が完了です。
2. Modelにて設定
使いたいModelで下記のようにextend
を使って読み込みます。
class Model
extend OrderAsSpecified
end
3. whereを使うときに追記する
使うときは、where
に続いて取得順を定義すればOK。
where
でID指定で記事を取ったあと、そのIDの順番でソートしたい場合は下記の通りとなります。
id_array = [3,4,1,2]
Model.where(id: id_array).order_as_specified(id: id_array)
もちろん、limit
などをつなげることも可能です。
id_array = [3,4,1,2]
Model.where(id: id_array).order_as_specified(id: id_array).limit(5)
https://stackoverflow.com/questions/8505079/activerecord-order-by-external-array/29039262#29039262
具体的には、下記のようにorder
句を生成してくれているようです。
ORDER BY ID='3' DESC, ID='4' DESC, ID='1' DESC, ID='2' DESC
まとめ
あらかじめwhereにて取得したい順にしておいても、Railsでは関係なくソートされてしまいます。
やはり何らかの理由があって「この順番がよい」というときには重宝する方法ではないでしょうか。
ぜひgem「order_as_specified」も使ってみてくださいね!
コメント