1

列を介して ActiveRecord モデルを管理しようとしていpriority:integerます。行をafter_updateafter_createフックで管理して、順序をきちんと整理したいと考えています。

2 つのニーズがあります。

  1. アイテムの現在のリストを取得し、それらの優先度属性を更新して、厳密な順序に従います。例: 上記の優先度列を持つ 3 つのアイテムのリスト。

    [a.priority = 4, b.priority = 66, c.priority = 92]
    

    になる

    [a.priority = 1, b.priority = 2, c.priority = 3]
    
  2. リストの中央に新しい行が追加されたことを反映して、すべての行の優先度を更新します。

    [a.priority = 1, b.priority = 2, c.priority = 3, d.priority = 4]
    

    e.priority = 2新しいリストを作成する

    [a.priority = 1, e.priority = 2, b.priority = 3, c.priority = 4, d.priority = 5]
    

github リポジトリ: https://github.com/digitalcake/priority_manager

4

2 に答える 2

2

最初のケースでは、次のようなことができます

Model.order("priority ASC").each_with_index {|m,i| 
  m.update_attribute(:priority, i+1) }

そして2つ目

Model.where("priority >= ?", new_priority).each {|m| 
  m.update_attribute(:priority, m + 1) }

とはいえ、順序だけに関心があり、リスト上の絶対位置には関心がない場合は、整数を使用して優先順位を格納する代わりに、浮動小数点数を使用した方が効率的です。間に入れたいオブジェクトの優先順位の間に it 値を割り当てて、行を挿入します。IEは、 bc間にaをそれぞれの優先度pbpcで挿入し、それにpa = ( pc + pb ) / 2の優先度を割り当てます。

このようにして、全体的な順序はそのまま残りますが、新しい行を挿入するたびに、すべてのオブジェクトを優先度の高いものに変更して再保存する必要はありません。

于 2013-02-16T02:43:06.377 に答える
0

私が構築しているアプリの 1 つで、まったく同じシナリオを処理しました。受け入れられた回答の解決策は、コールバックを再帰的に使用して更新しようとしているオブジェクトを呼び出すため、機能しませんでした(update_attributes内)。また、クエリ内の self オブジェクトの id をスキップする必要があります。

これが私が最終的に行っている方法であり、すべてのケースで機能するようです。

after_commit :order_priorities, :if => :persisted?
after_destroy :handle_priorities_when_destroyed

def order_priorities
    correct_priority = MyModel.where('id != ? AND priority < ?',id,priority).count + 1
    MyModel.where.not(id:id).order(:priority).each_with_index {|x,i|
        if x.priority < priority
            x.update_column(:priority, i+1) 
        else
            x.update_column(:priority, i+2)
        end
    }
    self.update_column(:priority,correct_priority) 
end

def handle_priorities_when_destroyed
    MyModel.where.not(id:id).order(:priority).each_with_index {|x,i|
            x.update_column(:priority, i+1)
    }
end

ここでは after_commit コールバックを使用しているため、メソッドで定義した自分自身に correct_priority を設定できます。コミット中に値が上書きされるため、他のコールバックは機能しません。

update_column を使用して、不要なコールバックがスキップされるようにします。

ロジックは自明です。

于 2016-03-01T04:42:00.250 に答える