49hack

見習いエンジニアが魔法使いになるまで

指定した順序どおりにレコードを取得する

作業環境

使用しているRailsは4.1.1です。

$ rails -v
Rails 4.1.1

一番手っ取り早い方法

例えば、ユーザを指定のid順に取得したい場合は、

# 普通にid渡してもできない
user_ids = [4,2,3,1]
users = User.where(id: user_ids)
#=> [1,2,3,4]

# MysqlのOREDER BY FIELD句を使う
user_ids = [4,2,3,1]
users = User.where(id: user_ids).order("FIELD(id, #{user_ids.join(',')})")
#=> [4,2,3,1]

クラスを拡張する方法

頻繁に使用する場合はクラスを拡張して利用したほうがいいと思います。

module Extensions::ActiveRecord::FindByOrderedIds
  extend ActiveSupport::Concern
  module ClassMethods
    def find_ordered(ids)
      order_clause = "CASE id "
      ids.each_with_index do |id, index|
        order_clause << sanitize_sql_array(["WHEN ? THEN ? ", id, index])
      end
      order_clause << sanitize_sql_array(["ELSE ? END", ids.length])
      where(id: ids).order(order_clause)
    end
  end
end

ActiveRecord::Base.include(Extensions::ActiveRecord::FindByOrderedIds)

Person.find_ordered([2, 1, 3]) # => [2, 1, 3]

How to select database records in an arbitrary order - Justin Weiss より抜粋

ちなみに

Railsのmasterにはこの手のメソッドが組み込まれているそうです。

Model.where(id: ids).order(['field(id, ?)', ids])

参考