Forum: Rails Germany "Komplexere" Formular Validation über AJAX (inklusive Tests)

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
5d7c8b8f2de06c07b2bf0848d20ce71f?d=identicon&s=25 Christian Beier (cbeier)
on 2009-02-13 09:12
Hallo,

ich arbeite gerade an einem Formular zum Anlegen eines neues Eintrages
und möchte dies mittels AJAX noch vor der Speicherung auf eventuelle
Duplikate überprüfen. Wir ein ähnlicher Eintrag gefunden, soll der
Nutzer darauf hingewiesen werden und auswählen, ob der gefundene Eintrag
ein Duplikat ist.

Die Prüfung sollte am besten noch vor dem Absenden des Formulars
stattfinden, damit sich der Nutzer im Zweifelsfall es sich sparen kann,
das gesamte restliche Formular auszufüllen. Sobald die für die
Validierung nötigen Parameter (SSID, Adresse, PLZ/Ort) in das Formular
eingegeben wurde, soll die Überprüfung stattfinden und darunter eine
Meldung ausgegeben werden, wenn ein ähnlicher Eintrag gefunden wurde.

Theoretisch müsste ich ja die vier Felder per JavaScript überwachen und
sobald in allen eine value vorhanden ist, dann einen Request (inklusive
der Inhalte aus den bis dahin ausgefüllten Felder) auf den Controller
mit der Validierung absetzen. Der Controller (mit Hilfe des Models) auf
Duplikate und gibt ggf. die Meldung zurück, welche per JS ins DOM
eingefügt wird.

Das Absenden des Formulars an sich soll nicht über AJAX laufen, sondern
nur die Validierung(en). Später prüft dann der Controller zum Eintragen
der Daten, ob eine Validierung durchgeführt wurde. Wenn nicht (weil kein
JavaScript aktiviert war), wird die Validierung im Controller
durchgeführt und ggf. ein Fehler zurückgeliefert. Zusätzlich müssten
hier noch Überprüfungen stattfinden, ob ein Duplikat gefunden wurde und
ob der Nutzer eine Checkbox ausgewählt hat die besagt, dass der
gefundene Eintrag kein Duplikat ist.

Soweit sind derzeit meine theoretischen Grundgedanken zu dem Ablauf und
Realisierung des Szenarios. Ist dies mit Rails Boardmitteln möglich oder
soll in den nötigen JS-Code lieber gleich selber schreiben? Oder bin ich
ganz auf dem Holzweg mit meinen Gedanken? In den ganzen Rails Büchern
wird AJAX ja immer auf ganze Formulare angewendet. Bisher habe ich
leider noch kein Beispiel für eine Validierung eines einzelnen Feldes
(und in meinen Beispiel von eine Gruppe von Feldern) gefunden.

Gibt es in Rails eine Möglichkeit, dieses Szenario mittels Tests
(Functional und/oder Integration) abzudecken? Theoretisch müsste ich ja
das Ausfüllen eines "halben" Fomulares simulieren und überprüfen, ob
bestimmte Ausgaben (z.B. der Hinweis) ausgegeben wurden.


Viele Grüße,
Christian
64502c61ed41ff9e917499a2347dd9fe?d=identicon&s=25 Werner Laude (Guest)
on 2009-02-13 09:30
(Received via mailing list)
Hallo Christian.. was fürn Aufwand..

vielleicht fragst du erst mal ein relevantes Feld ab. Dies kannst du
mit Ajax checken und füllen lassen.
Ist es schon vorhanden =>
a. message  => Frage ja / nein
b. nach request wird der Rest aus der db geholt und die Felder
gefüllt / leeres Formular

Wäre das nicht sinnvoller..?

Gruß
Werner


Am 13.02.2009 um 09:12 schrieb Christian Beier:
5d7c8b8f2de06c07b2bf0848d20ce71f?d=identicon&s=25 Christian Beier (cbeier)
on 2009-02-13 10:12
Hallo Werner,

für die Validierung brauche ich jedoch die vier Felder zusammenhängend,
damit die Überprüfung zuverlässig funktioniert. Das ist ein
Zusammenspiel aller vier Felder.
Oder wie meinst du das genau?


Viele Grüße,
Christian

Werner Laude wrote:
> Hallo Christian.. was f�rn Aufwand..
>
> vielleicht fragst du erst mal ein relevantes Feld ab. Dies kannst du
> mit Ajax checken und f�llen lassen.
> Ist es schon vorhanden =>
> a. message  => Frage ja / nein
> b. nach request wird der Rest aus der db geholt und die Felder
> gef�llt / leeres Formular
>
> W�re das nicht sinnvoller..?
>
> Gru�
> Werner
>
>
> Am 13.02.2009 um 09:12 schrieb Christian Beier:
Bce1d1b7c3ec7b577dcb42e254899e6b?d=identicon&s=25 Michael Schuerig (Guest)
on 2009-02-13 10:34
(Received via mailing list)
On Friday 13 February 2009, Christian Beier wrote:

> Theoretisch müsste ich ja die vier Felder per JavaScript überwachen
> und sobald in allen eine value vorhanden ist, dann einen Request
> (inklusive der Inhalte aus den bis dahin ausgefüllten Felder) auf den
> Controller mit der Validierung absetzen. Der Controller (mit Hilfe
> des Models) auf Duplikate und gibt ggf. die Meldung zurück, welche
> per JS ins DOM eingefügt wird.

Schau mal, ob dir dieses Plugin hilft

  http://code.google.com/p/fluxvalidator/

Wie gut es ist, weiss ich nicht, weil ich es selbst nie verwendet habe.

Wenn du nicht auf Prototype.js festgelegt bist, hilft vielleicht auch
dieses

  http://bassistance.de/jquery-plugins/jquery-plugin...

Allerdings: Du solltest dich bei dieser Aufgabenstellung darauf
einstellen, dass es das ein oder andere Problem(chen) geben wird, zu
dessen Lösung du die beteiligten Bauteile verstehen musst.

Michael

--
Michael Schuerig
mailto:michael@schuerig.de
http://www.schuerig.de/michael/
5d7c8b8f2de06c07b2bf0848d20ce71f?d=identicon&s=25 Christian Beier (cbeier)
on 2009-02-14 11:01
Hallo Michael,

vielen Dank für die Links. Habe sie mir gestern Abend noch etwas
angeschaut und werde mich jetzt eingehender damit beschäftigen. Gerade
das jQuery Plugin find ich gut, da ich das Rails Projekt eh schon auf
jQuery umgestellt habe (mit jQuery habe ich noch am meisten
"Erfahrung").

Ich glaube die größte Schwierigkeit wird es sein, die vier Felder auf
Eingaben "zu überwachen" um zum richtigen Zeitpunkt die Validierung
anzustoßen und auch die Eingaben an den Rails-Controller zu übertragen.

Von meinen Gedanken her liege ich richtig, oder? Also auch damit, eine
zusätzliche "public" Methode im Controller zu definieren, die den
AJAX-Request entgegennimmt, mit dem Model verarbeitet und dann das
Ergebnis wieder zurück liefert. Oder gibt es dafür in Rails eine
elegantere Lösung?


Viele Grüße,
Christian

Michael Schuerig wrote:
Bce1d1b7c3ec7b577dcb42e254899e6b?d=identicon&s=25 Michael Schuerig (Guest)
on 2009-02-14 11:43
(Received via mailing list)
On Saturday 14 February 2009, Christian Beier wrote:
> Ich glaube die größte Schwierigkeit wird es sein, die vier Felder auf
> Eingaben "zu überwachen" um zum richtigen Zeitpunkt die Validierung
> anzustoßen und auch die Eingaben an den Rails-Controller zu
> übertragen.

Bei jQuery bin ich da nicht auf der Höhe, bin aber sicher, dass es die
nötigen Mittel gibt. Grundsätzlich musst du Client-seitig drei
Teilprobleme lösen: (1) Erkennen, dass sich die relevanten Felder
geändert haben. (2) Ajax-Request mit den serialisierten Feldern. (3)
Anzeige des Validierungsergebnisses.

Dabei solltest du noch sicherstellen, dass nicht jeder Tastendruck einen
Request an den Server auslöst. Das kannst du mit einem Timer erreichen,
der bei jeder Änderung neu gestartet wird und daher erst dann auslöst,
wenn es zwar eine Änderung gab, sich aber eine bestimmte Zeit nichts
mehr geändert hat. Mit Prototype habe ich das in einem eigenen
Validator mal mit der angehängten Klasse gemacht.

Michael


Event.UserActionObserver = Class.create();

Event.UserActionObserver.ignoredKeys = [
  Event.KEY_TAB,
  Event.KEY_RETURN,
  Event.KEY_ESC
];

Event.UserActionObserver.prototype = {
  initialize: function(container, callback, options) {
    this.options = Object.extend({
      latency: 0.4,
      events: ['keypress', 'change']
    }, options);

    this.container = $(container);
    this.callback = callback;
    this.latency = this.options.latency * 1000;
    this.timer = null;
    this.notifyCallback = this._notifyCallback.bind(this);
    this.onAction = this._onAction.bindAsEventListener(this);
    this.start();
  },

  start: function() {
    var events = this.options.events;
    for (var i = 0; i < events.length; i++) {
      Event.observe(this.container, events[i], this.onAction);
    }
  },

  stop: function() {
    var events = this.options.events;
    for (var i = 0; i < events.length; i++) {
      Event.stopObserving(this.container, events[i], this.onAction);
    }
  },

  _onAction: function(event) {
    if (Event.UserActionObserver.ignoredKeys.include(event.keyCode)) {
      return;
    }
    if (this.timer) {
      clearTimeout(this.timer);
    }
    this.timer = setTimeout(this.notifyCallback, this.latency);
  },

  _notifyCallback: function() {
    this.callback();
  }
};

--
Michael Schuerig
mailto:michael@schuerig.de
http://www.schuerig.de/michael/
5d7c8b8f2de06c07b2bf0848d20ce71f?d=identicon&s=25 Christian Beier (cbeier)
on 2009-02-19 16:09
Hallo,

ich melde mich zurück mit einer Erfolgsmeldung und einer Frage zu meiner
oben genannten Problematik. Allerdings habe ich es mir bei der
Überprüfung mit AJAX etwas einfacher gemacht und überprüfe die vier
Felder immer nachdem diese verlassen wurden, ob alle benötigten Felder
ausgefüllt wurden. Also nicht direkt bei der Eingabe. Auch die Anzeige
einer entsprechenden Meldung funktioniert und wird an der richtigen
Stelle eingefügt.

Jetzt habe ich aber eine Frage zu der Realisierung dieser Funktionalität
(Prüfung auf Duplikate und Ausgabe einer Meldung mit den gefundenen
Duplikaten unter einem Feld) ohne JavaScript (Fallback-Lösung). Ich habe
es mir wie folgt vorgestellt:
Beim Abschicken des Formulars wird überprüft, ob die Validierung bereits
von der JS-Lösung durchgeführt wurde (mittels eines hidden Feldes). Wenn
nicht, soll die Action für die Validierung aufgerufen werden. Der für
mich etwas knifflige Teil kommt jetzt: Wenn ein Duplikat gefunden wurde,
soll der Nutzer wieder das Formular der "new"-Action angezeigt bekommen.
Zusätzlich soll ein Partial (welches die Meldung enthält) an einer
bestimmten Stelle des Quellcodes eingeblendet werden.

Im Moment rufe ich die Action für die Validierung innerhalb der
"create"-Action auf:

  def create
    @test = Test.new(params[:test])

    # Check duplicate
    if @test[:checkDuplicate].blank?
      check_duplicate(@hotspot)

    end

    respond_to do |format|
      if @test.save
        flash[:notice] = 'Der Datensatz wurde erfolgreich gespeichert.'
        format.html { redirect_to(@test) }
        format.xml  { render :xml => @test, :status => :created,
:location => @test }
      else
        format.html { render :action => "new" }
        format.xml  { render :xml => @test.errors, :status =>
:unprocessable_entity }
      end
    end
  end

Jetzt komme ich aber leider nicht weiter dass die "news"-Action mit dem
Partial angezeigt wird. Denn innerhalb der "create"-Action darf ich ja
nur einmal den render Befehl verwenden. Und wenn die Überprüfung bereits
stattgefunden hat, soll ja weiterhin der restliche Code (Eintragung in
der Datenbank und je nach Ergebnis die show Seite angezeigt werden oder
das Formular mit den Fehlern) ausgeführt werden. Wisst ihr was ich
meine?


Viele Grüße,
Christian
This topic is locked and can not be replied to.