はじめに
こんにちは、HappyManaです。
Railsで並び替えをしたいときに使うgemで、大きくacts_at_listとranked-modelがあります。
この2つのgemの違いがわかりにくかったため、紹介するとともに違いを書いていきます。
並び替え用のdbカラムは、row_orderカラムとします。
dbに入る値が異なる
最も異なるのがこれです。
他にもいろいろ違いはありますが、1番大きな違いなので、これを説明していきます。
acts_as_list
acts_as_listでは、カラムに1、2など「そのレコードが何番目か」が入っています。
例えば、現在3番目のレコードを2番目に並べ替えたいとき、acts_as_listでは、2番目と3番目のレコードのrow_orderカラムが変更されます。
id | row_order |
---|---|
1 | 1 |
2 | 2 |
3 | 3 |
↓
id | row_order |
---|---|
1 | 1 |
2 | 3 |
3 | 2 |
そのため、並べ替えたい先の番号より後の番号のレコードはすべて更新されます。
値の更新では、対象のレコードと、それ以外の変更する必要のあるレコードをwhereで絞り込んで+1もしくは-1するというUPDATE文になるので、クエリ数は2回で済むようになります。
今回の例では、id=2と3の2レコードしかありませんが、100行になっても2回で済みます。
ただし、デメリットとして、3レコードしかない状況で、「100」などの最後尾の番号より大きい値を入れると、最後尾の番号ではなく、100番という絶対的な値が入るというデメリットがあります。
ranked-model
一方で、ranked-modelは、カラムに-1073741823、126322567など「そのレコードの重み」が入っています。
これをすると、重みが軽い順に並びます。
これによって、「1レコードを並び替えた時に、そのレコードのみUPDATEされる」という処理になります。
例えば、現在3番目のレコードを2番目に並べ替えたいとき、ranked-modelでは、1番目と2番目のrow_orderカラムの値の合計/2の値が3番目のレコードのrow_orderカラムに入ります。
id | row_order |
---|---|
1 | 100 |
2 | 200 |
3 | 300 |
↓
id | row_order |
---|---|
1 | 100 |
2 | 200 |
3 | 150 |
そのため、対象のレコードのみUPDATEされます。
ただし、1番目と2番目のrow_orderカラムの値にすき間がない場合、重みが振り分けられます。
そうなると、すべてのレコードのrow_orderカラムの値が変わるため、クエリ数がN+1になります。
まあINTEGER型なので、-2147483647~2147483647の間で均等に割り振られるため、頻繁にN+1は起きないと考えられます。
デメリットとしては、上で挙げた重みを振り分ける際にクエリ数がN+1になる可能性があるということ、またすべてのレコードを確認しないとそのレコードが何番目かわからないということがあります。
おわりに
acts_as_listとranked-modelの違いを書きました。
それぞれで処理の内容が違って興味深かったです。
個人的には、関係ないレコードはUPDATEされないranked-modelの方が好みではあるのですが、2クエリでまとめてUPDATEするacts_as_listも魅力的ではあるなと思いました。