Document ID: /fineweb-2-swissfilter-quality_10-filterrobots/filtered/03300.jsonl.gz/2405

Die Validation von Benutzereingaben betrifft nicht nur das Aufdecken von Tippfehlern, sondern verhindert auch, dass unpassende Werte das System instabil machen. Eine durchdachte Datenvalidation kann zudem auch Spambots einen Strich durch die Rechnung machen.
Ruby on Rails bringt schon viele Hilfsmittel mit, um Modeldaten beim persistieren zu validieren. Es fehlt jedoch eine Möglichkeit, um beispielsweise zu überprüfen, ob der eingegebene Vor- und Nachname unterschiedlich ist. Auch nach längerer Suche habe ich niemanden in den Telefonbüchern entdecken können, welcher den selben Vor- und Nachname hat. Wenn ihr jemanden findet, meldet dich doch bei mir.
Ganz nach dem Prinzip, der testgetriebenen Entwicklung (TDD), wird erst einmal ein Test erstellt, welcher die Anforderungen definiert und später das Resultat überprüft. Aber Moment mal, hat nicht der dänische Autor von Rails, David Heinemeier Hansson, testgetriebene Entwicklung in seinem Blog für tot erklärt? Der Test beinhaltet ein Modell mit den beiden Feldern, Vor- und Nachname, welches als Mock-Objekt dient. So wie ich das verstehe, ist genau dieses Mock-Objekt einer der Gründe, weshalb der Rails-Erfinder TDD nicht mehr mag.
Ist dieser Validator in ein Rails-Projekt eingebettet, so wäre es sinnvoller einen Test für die jeweiligen Modelle zu schreiben, welche diese Validation voraussetzen. Diese Tests zu den Modellen sind kontextbezogen und überprüfen somit genauer die spezifische Anforderung an die Software. Extrahiert man jedoch diesen Validator, beispielsweise in ein separates Gem, so würde sich dieser Test mit dem Mock-Objekt wieder rechtfertigen. Ein abgeschlossenes Modul, welches vielleicht in mehreren Projekten verwendet wird, soll ja getestet sein.
require 'test_helper' class ValuesNotEqualValidatorTestModel include ActiveModel::Validations validates :forename, :surname, values_not_equal: true attr_accessor :forename attr_accessor :surname end class ValuesNotEqualValidatorTest < ActiveSupport::TestCase test "if two equal values aren't valid" do model = ValuesNotEqualValidatorTestModel.new model.forename = 'friedrich' model.surname = 'friedrich' assert_not model.valid? end test "if two different values are valid" do model = ValuesNotEqualValidatorTestModel.new model.forename = 'fritz' model.surname = 'friedrich' assert model.valid? end end
Nun aber zum Validator selbst. Dadurch, dass wir mehrere Felder überprüfen möchten, erweitern wir den EachValidator. Dieser ruft die Methode
validate_each für jedes Feld auf. Ist ein Feld einem zuvor kontrollierten Feld gleich, so wird eine Fehlermeldung generiert, welche sich Rails i18n-Funktionalität bedient.
class ValuesNotEqualValidator < ActiveModel::EachValidator def validate(record) @past = Hash.new super end def validate_each(record, attribute, value) @past.each do |k, v| if v == value record.errors.add(attribute, I18n.t('errors.messages.should_not_be_equal_to', other: record.class.human_attribute_name(k))) end end @past[attribute] = value end end