自分のブログの転載記事です。
はじめに
ActiveRecordのorderメソッドに引数を複数渡せることは有名だと思います。
ですが「複数の値を渡すとどのようにソートされるのか」について具体的に言及している記事が少ないように感じたので、簡単な例を挙げてまとめてみたいと思います。
(自分の検索能力が低いだけかも知れませんが)
検証準備
複数のカラムを持つUserテーブルを定義して、以下のレコードを格納します。
id | name | gender | role |
---|---|---|---|
1 | Alice | 2 | 1 |
2 | Bob | 1 | 1 |
3 | Carol | 2 | 2 |
4 | Dave | 1 | 2 |
カラムはそれぞれ、名前、性別、ロールです。それぞれ単なる検証用の値なので、深い意味はありません。 | |||
そしてUserモデルの中に、以下のメソッドを定義します。 |
class User < ApplicationRecord
def print
puts "id:#{id} name:#{name} gender:#{gender} role:#{role}"
end
end
これで準備は完了です。
引数が一つの場合
まずは簡単な例からやってみましょう。nameをorderの引数にする場合です。
# 名前昇順
irb(main):001:0> users = User.all.order(:name)
irb(main):002:0> users.each {|user| user.print}
id:1 name:Alice gender:2 role:1
id:2 name:Bob gender:1 role:1
id:3 name:Carol gender:2 role:2
id:4 name:Dave gender:1 role:2
ユーザーの名前はアルファベット順になっているので、このような結果になります。
genderやroleを引数にした場合は以下のとおりです。
# 性別昇順
irb(main):001:0> users = User.all.order(:gender)
irb(main):002:0> users.each {|user| user.print}
id:2 name:Bob gender:1 role:1
id:4 name:Dave gender:1 role:2
id:1 name:Alice gender:2 role:1
id:3 name:Carol gender:2 role:2
# ロール昇順
irb(main):003:0> users = User.all.order(:role)
irb(main):004:0> users.each {|user| user.print}
id:1 name:Alice gender:2 role:1
id:2 name:Bob gender:1 role:1
id:3 name:Carol gender:2 role:2
id:4 name:Dave gender:1 role:2
gender, roleの場合、それぞれが1, 2という順で並びます。
引数が2つの場合
ここからが本題です。引数が複数渡された場合、どのような順序になるのでしょう。
# 性別昇順、ロール昇順
irb(main):001:0> users = User.all.order(:gender, role: :asc)
irb(main):002:0> users.each {|user| user.print}
id:2 name:Bob gender:1 role:1
id:4 name:Dave gender:1 role:2
id:1 name:Alice gender:2 role:1
id:3 name:Carol gender:2 role:2
# 性別昇順、ロール降順
irb(main):003:0> users = User.all.order(:gender, role: :desc)
irb(main):004:0> users.each {|user| user.print}
id:4 name:Dave gender:1 role:2
id:2 name:Bob gender:1 role:1
id:3 name:Carol gender:2 role:2
id:1 name:Alice gender:2 role:1
最初に渡される引数は性別で、後に渡される引数はロールです。
その場合、性別がまず優先してソートされ、1が先、2が後という順序になります。
その後、第二引数として渡されたロールの順序によってソートされているのがわかるでしょうか。
つまりorderメソッドに引数を複数渡す場合、「先に渡した引数が優先条件としてソートされ、その後、後に渡した引数を条件としてソートされる」ということになります。
もうひとつの例として、ロール、性別の順で引数を渡した場合を見てみます。
# ロール降順、性別昇順
irb(main):001:0> users = User.all.order(role: :desc, gender: :asc)
irb(main):002:0> users.each {|user| user.print}
id:4 name:Dave gender:1 role:2
id:3 name:Carol gender:2 role:2
id:2 name:Bob gender:1 role:1
id:1 name:Alice gender:2 role:1
# ロール降順、性別降順
irb(main):001:0> users = User.all.order(role: :desc, gender: :desc)
irb(main):002:0> users.each {|user| user.print}
id:3 name:Carol gender:2 role:2
id:4 name:Dave gender:1 role:2
id:1 name:Alice gender:2 role:1
id:2 name:Bob gender:1 role:1
第一引数がロールの降順なので、2→1としてソートされた後、性別でソートされていますね。
以上、複数の引数でorderした場合の簡単な例でした。