Aktualisierung: 22. Februar 2023 – Autocomplete für Kategorien ist inzwischen implementiert
Turbo bietet die Technologie in einer Ruby on Rails Web-Anwendung, um dynamischer mit den Nutzern zu interagieren. Wie lässt sich die Eingabe des Autors eines Zitates damit vereinfachen? Zur Implementierung von Autocomplete gibt es viele Tutorials im Netz, z.B. das YouTube-Video Ruby on Rails #60 Hotwire Turbo Streams Autocomplete Search von Yaroslav Shmarov. Ich hatte ein wenig Mühe das gefundene in meine real-world Web-Anwendung zu übernehmen. Aber beim zweiten Versuch konnte ich die Teile besser zusammensetzen, und das möchte ich hier zeigen. Vielleicht hilft es anderen Anfängern ein wenig?
Im zitat-service.de soll der Nachname des Autors automatisch ergänzt werden, wenn die Eingabe eindeutig ist und auch aus der Liste anklickbar sein. Die erste Umsetzung erfolgte mit einem zusätzlichen Formular für den Namen des Autors, Session-Variablen zur Synchronisierung mit dem Formular der übrigen Felder des Zitats. Das war überhaupt nicht rails-like, fehleranfällig und hatte das grundsätzliche Problem, dass bei der Auswahl aus der Liste, die bisher getätigten Eingaben bei dem Klick auf den Link verloren gingen.
Die Implementierung ist hier vereinfacht erläutert. Der komplette Quellcode und die Möglichkeit eine Docker Test-Instanz aufzusetzen sind unter
Der Kommentar von Koen Handekyns in Syntax for returning multiple turbo streams ist ein hilfreicher Hinweis, wie man mit einem Render-Aufruf mehrere Turbo-Stream-Updates zur gleichen Zeit auslösen kann. Andere Teile des Puzzles sind:
quotation[author_id]
für die ID des Autors Quotation.author_id
author
, in dem die Anfangsbuchstaben des Autorennamens eingegeben werden und in dem dann der gewählte Autor angezeigt wirdoninput: "this.form.requestSubmit()"
div#authors_list
mit einer Liste von bis zu zehn gefunden Autoren gefüllt wird, oder bleibt leer und verschwindet damitcreate()
und update()
im QuotationsController verwenden den :commit
Parameters des Submit-Buttons, um zu unterscheiden, ob der Request vom Abschicken des gesamten Formulars oder von der Eingabe von Text im Autorenfeld stammtturbo_author()
im QuotationsController ausgelöst:
quotation[author_id]
gesetzt und und das Feld author
mit Name, Vorname und Beschreibung gefülltold_author_id
mit der vorher im Formular gespeicherte Autoren-ID verglichen)<li>
, die GET-Requests beim Anklicken eines Links rufen die Controller-Methode author_selected()
auf, die dann wieder die zwei Updates, wie bei genau einem gefunden Autor auslöstHier der entscheidene Abschnitt aus QuotationsController.update()
:
if params[:commit]
logger.debug { "update() quotation #{@quotation.inspect}" }
if @quotation.update(quotation_params)
hint = "Das Zitat wurde aktualisiert."
# give hint, e.g. if author autocomplete field is not completed
hint << " Der Autor „#{Author.find(@quotation.author_id).name}” wurde nicht geändert." if @authors.count != 1
return redirect_to @quotation, notice: hint
else
render :edit, status: :unprocessable_entity
end
else
turbo_author(old_author_id)
turbo_category(nil, old_category_ids, Category.check(@quotation))
render turbo_stream: turbo_stream_do_actions
end
Mit dieser Lösung sind Session Variablen nicht mehr erforderlich. Der ausgewählte Autor steht im hidden field mit seiner ID. Der Code zum Erstellen und Aktualisieren unterscheidet sich nicht wesentlich. Ein Klick auf einen Link in der Liste der gefundenen Autoren löst zwar einen GET-Request aus. Aber innerhalb der Seite werden nur die beiden Turbo-Frames aktualisiert, die anderen Formulareingaben bleiben bestehen.
Inzwischen hat auch die Eingabe der Kategorien ein Autocomplete erhalten :)