2016-07-30 2 views
0

In meiner Rails-App habe ich eine Liste erstellt, die es dem Benutzer ermöglicht, Datensätze durch Klicken/Ziehen/Ablegen zu sortieren. Nach jeder Nachbestellung führe ich die Aktualisierungsaktion aus und gebe die old_index und new_index des verschobenen Elements weiter und sortiere die gesamte Liste neu. Die Anwendung funktioniert wie erwartet, solange ich die Objekte nicht sehr schnell neu anordne. Meine Frage ist, wie kann ich das Design verbessern, das ich für eine schnelle Sortierung durch den Benutzer berücksichtigen muss und diese Änderungen genau widerspiegeln? Ich versuche auch zu verhindern, dass der Benutzer auf einen "Speichern" -Button klicken muss - wenn es aber notwendig ist, kann ich das implementieren.In Rails kann die Ajax-Sortierung nicht mit dem Verschieben von Elementen in meiner Liste Schritt halten

Update-Aktion

 def update 

     if @list_item.present? 

      # update the modified item, and then update all items after that are affected 
      old_index = params[:old_rank].to_i 
      new_index = params[:sequence_rank].to_i 

      @list_item.update(sequence_rank: new_index) # update the moved item 

      # move element down and shift others up 
      if old_index < new_index 
      @list.list_items.where('sequence_rank <= (?) AND list_items.id \ 
       <> (?) AND sequence_rank > (?)', new_index, @list_item.id, 0) 
       .each_with_index do |item,index| 
       item.update(sequence_rank: item.sequence_rank-1) 
      end 
      # move element up and shift elements down 
      else 
      @list.list_items.where('sequence_rank >= (?) AND list_items.id \ 
      <> (?) AND sequence_rank < (?)', new_index, @list_item.id, old_index+1) 
      .each_with_index do |item,index| 
       item.update(sequence_rank: item.sequence_rank+1) 
      end 
      end 

     end 

     render nothing: true 

     end 

auch folgende gem Ich verwende: https://github.com/scttdavs/sortable-rails

Antwort

0

Es gibt einige Verbesserungen in Ihrem Code vorgenommen werden könnten, aber sie würden die Wurzel Problem der nicht lösen Backend hält nicht mit den UI-Updates Schritt.

Wie Sie mehrere Datenbankabfragen durchführen, die zusammen benötigen, um Daten in einem konsistenten Zustand zu verlassen, sollte dies in einer Transaktion erfolgen:

if @list_item.present? 
    # update the modified item, and then update all items after that are affected 
    old_index = params[:old_rank].to_i 
    new_index = params[:sequence_rank].to_i 

    @list_item.transaction do 
    @list_item.update(sequence_rank: new_index) 

    if old_index < new_index 
     ... 
    end 
    end 
end 

Dieses Stück Code

.each_with_index do |item, index| 
    item.update(sequence_rank: item.sequence_rank - 1) 

ist langsamer als es könnte sein. Dies liegt daran, dass each_with_index Datensätze aus der Datenbank abrufen und in eine ActiveRecord-Modellklasse umbrechen muss. Die item.update ruft dann eine separate SQL-Anweisung für jeden Datensatz auf. Eine Möglichkeit, dies zu verbessern, wäre die Ausgabe einer einzigen SQL-Aktualisierungsanweisung, die den Wert sequence_rank für alle betroffenen Datensätze verringert.

sql = "UPDATE list_items SET sequence_rank = sequence_rank - 1 WHERE ..." 
@list_item.connection.execute(sql) 

Die Abfrage sequence_rank erhöht wird wahrscheinlich mit der oben zusammengefügt werden kann.

Bei der Behebung des Root-Problems gibt es mindestens zwei Lösungen. Eine besteht darin, die UI der Liste zu deaktivieren, bis die Ajax-Aktualisierungsanforderung zurückgegeben wird. Auf diese Weise stellen Sie sicher, dass die Updates seriell sind. Es hat jedoch einige Auswirkungen auf die Benutzerfreundlichkeit.

Eine weitere Möglichkeit besteht darin, die Aktualisierungen auf dem Frontend zu speichern und sie in Intervallen oder bei einigen anderen Ereignissen zu speichern, wobei wiederum die relevante Benutzeroberfläche für die Dauer des Ajax-Aufrufs deaktiviert wird. Dies ist komplexer zu implementieren, hat aber möglicherweise einen geringeren Einfluss auf die Benutzerfreundlichkeit.