ranked-modelを使うときは :with_sameオプションを付けよう

前置き

自作中のTODOアプリではタスクの表示順を自由に入れ替えできるようになっています。

f:id:naito-coding0322:20180922192059p:plain

indexページには User の Task 一覧を表示

表示の順番はranked-model gemを使って :row_order の値で制御

それぞれの Task はjQueryUIのsortableを導入してドラッグ&ドロップで入れ替えが可能

という感じです。

class Task < ApplicationRecord
  include RankedModel
  belongs_to :user
  scope :donetask,  -> { where(:done => false ) }
  ranks :row_order, :scope => :donetask
end


問題点

並び替えが上手くいかないときがある。

並び替えをしてページを更新すると、ひとつ下にズレたりすることがたびたびありました。
ログを見ると一応 :row_order の値はきちんと更新されています。


原因

新規にテストユーザーを作成し、タスクを4つ作成しました。
DB Browserで確認します。
f:id:naito-coding0322:20180922193453p:plain

1番目のタスクを1つ下(2と3のあいだ)へ移動すると :row_order の値が更新されます。 f:id:naito-coding0322:20180922193637p:plain

本来であれば、1番目のタスクの:row_order の値は「1162961895」と「1655222771」の間で設定されなければいけません。

では「-2146624780」は何かというと、これはデータベースに登録されたすべての Task のなかで上から2番目に位置する数値です。
(実際には「すべての未完了なタスク」が正しいです。Taskモデルの画像参照。) データベース上の全てのタスクの中ではなく、そのユーザーが持っているタスクの中で順番を変更しないといけません。

対処法

ranks :row_orderに :with_same => :(親モデルの外部キー) というオプションを付け足します。

class Task < ApplicationRecord
  include RankedModel
  belongs_to :user
  scope :donetask,  -> { where(:done => false ) }
  ranks :row_order, :scope => :donetask, :with_same => :user_id ←これ
end

これでユーザーごと、つまり同じ user_id を持った複数の Task ごとにrow_orderの数値が割り振られるようになります。

長々と書きましたが、単純に「gemを使うときはREADMEを必ず読もうぜ」という話ですね。気をつけよう