22 Stimmen

Rails-Formular-Validierung

Ich habe eine Rails-App, mit der ein Benutzer eine Datenbankabfrage erstellen kann, indem er ein umfangreiches Formular ausfüllt. Ich fragte mich, die beste Praxis für die Überprüfung der Formularparameter in Rails. Zuvor habe ich meine results Methode (diejenige, an die das Formular gesendet wird), tun Sie Folgendes:

if params[:name] && !params[:name].blank?
  @name = params[:name]
else
  flash[:error] = 'You must give a name'
  redirect_to :action => 'index'
  return
end

Aber bei mehreren Formularfeldern wurde es lästig, dies für jedes einzelne Feld zu wiederholen. Ich konnte sie nicht einfach alle in eine Schleife stecken, um jedes Feld zu überprüfen, weil die Felder unterschiedlich eingerichtet sind:

  • eine einzige Taste: params[:name]
  • einen Schlüssel und einen Unterschlüssel: params[:image][:font_size]
  • nur erwarten, dass einige Formularfelder ausgefüllt werden, wenn ein anderes Feld gesetzt wurde

Etc. Dies war auch wiederholend, weil ich die flash[:error] für jeden fehlenden/ungültigen Parameter und die Weiterleitung an dieselbe URL für jeden einzelnen. Ich bin zur Verwendung einer before_filter die alle erforderlichen Formularparameter überprüft und nur dann true zurückgibt, wenn alles in Ordnung ist. Dann wird die my results Methode wird fortgesetzt, und die Variablen werden einfach zugewiesen, ohne dass eine Überprüfung stattfindet:

@name = params[:name]

In meinem validate_form Methode, habe ich Codeabschnitte wie den folgenden:

if (
  params[:analysis_type][:to_s] == 'development' ||
  params[:results_to_generate].include?('graph')
)
  {:graph_type => :to_s, :graph_width => :to_s,
   :theme => :to_s}.each do |key, sub_key|
    unless params[key] && params[key][sub_key]
      flash[:error] = "Cannot leave '#{Inflector.humanize(key)}' blank"
      redirect_to(url)
      return false
    end
  end
end

Ich frage mich nur, ob ich dies am besten angehe oder ob ich etwas Offensichtliches übersehe, wenn es um die Parametervalidierung geht. Ich befürchte, dass dies immer noch nicht die effizienteste Technik ist, denn ich habe mehrere Blöcke, in denen ich einen Wert zuweisen flash[:error] , dann auf dieselbe URL umleiten und dann false zurückgeben.

Edit zur Klarstellung: Der Grund, warum ich diese Validierung derzeit nicht in den Modellen vornehme, ist zweierlei:

  • Ich versuche nicht, Daten vom Benutzer zu sammeln, um eine Zeile in der Datenbank zu erstellen oder zu aktualisieren. Keine der Daten, die der Benutzer eingibt, wird nach der Abmeldung gespeichert. Sie werden direkt bei der Übermittlung verwendet, um die Datenbank zu durchsuchen und einige Daten zu generieren.
  • Das Abfrageformular nimmt Daten auf, die sich auf mehrere Modelle beziehen, und es nimmt andere Daten auf, die sich überhaupt nicht auf ein Modell beziehen. So sind z. B. der Diagrammtyp und das Thema, wie oben gezeigt, nicht mit einem Modell verbunden, sondern vermitteln lediglich Informationen darüber, wie der Benutzer seine Ergebnisse anzeigen möchte.

Bearbeiten, um eine verbesserte Technik zu zeigen: Ich verwende jetzt anwendungsspezifische Ausnahmen, dank Jamis Buck's Den richtigen Ausnahmeartikel aufziehen . Zum Beispiel:

def results
  if params[:name] && !params[:name].blank?
    @name = params[:name]
  else
    raise MyApp::MissingFieldError
  end

  if params[:age] && !params[:age].blank? && params[:age].numeric?
    @age = params[:age].to_i
  else
    raise MyApp::MissingFieldError
  end
rescue MyApp::MissingFieldError => err
  flash[:error] = "Invalid form submission: #{err.clean_message}"
  redirect_to :action => 'index'
end

0 Stimmen

Ich denke, Sie müssen params[:name] und !params[:name].blank? nicht in Ihren Bedingungen verwenden. !params[:name].blank? reicht aus. params[:name] gibt false zurück, wenn er nil ist (es gibt keinen solchen Parameter) und params[:name].blank? gibt true zurück, wenn er nil oder leer ist.

0 Stimmen

Sie erhalten einen NoMethodError. Ich könnte NilClass überschreiben und #blank? hinzufügen, nehme ich an. irb(main):002:0> params = {:a => 1, :b => 2, :c => 3} => {:c=>3, :a=>1, :b=>2} irb(main):003:0> !params[:name].blank? NoMethodError: undefinierte Methode `blank?' für nil:NilClass von (irb):3

0 Stimmen

Hier gibt es kein Ruby, nur Rails. gelöschtes Tag

25voto

Sie könnten es mit active_form ( http://github.com/cs/active_form/tree/master/lib/active_form.rb ) - einfach ActiveRecord ohne den Datenbankkram. Auf diese Weise können Sie alle AR's Validierung Zeug verwenden und behandeln Sie Ihr Formular wie Sie jedes andere Modell würde.

class MyForm < ActiveForm
  validates_presence_of :name
  validates_presence_of :graph_size, :if => # ...blah blah 
end

form = MyForm.new(params[:form])
form.validate
form.errors

0 Stimmen

Ist validates_presence_of :name ein Alias für validates :name, presence: true ? Ich habe nur die letztere in Rails Führer gesehen.

1 Stimmen

Um meine eigene Frage zu beantworten, ist der letztere Weg ein neuer Weg, um Validierungen in Rails 3 eingeführt zu tun. thelucid.com/2010/01/08/sexy-validierung-in-den-rand-schienen-schienen-3

8voto

Jamal Hansen Punkte 934

Sieht aus wie Sie tun die Validierung in der Steuerung, versuchen Sie es in das Modell, es ist besser geeignet, um diese Art von Sache.

5 Stimmen

Wie in den Empfehlungen der Leitfaden auch: "Validierungen auf Controllerebene können verlockend sein, werden aber oft unhandlich und sind schwer zu testen und zu warten. Wann immer möglich, ist es eine gute Idee, die Halten Sie Ihre Kontrolleure schlank Das wird die Arbeit mit Ihrer Bewerbung auf lange Sicht angenehm machen."

2voto

weston Punkte 1894

Wenn Sie das Problem heute noch einmal angehen würden, könnten Sie ein Modell für den Abfrageparametersatz erstellen und die in Rails eingebauten Validierungen verwenden. Rails 3 macht dies mit ActiveModel::Validations viel einfacher, siehe diese Stelle .

1voto

zawhtut Punkte 7967

Modell

class Person 
    include ActiveModel::Validations
    include ActiveModel::Conversion
    extend ActiveModel::Naming

    attr_accessor :name
    attr_accessor :email

    validates_presence_of :name,:message => "Please Provide User Name"
    validates_presence_of :email,:message => "Please Provide Email"
end

Beachten Sie, dass Sie das Modell nicht unbedingt speichern/bestehen lassen müssen, um es zu validieren.

Controller

@person.name= params["name"]
@person.email= params["email"]
@person.valid?

Wenn Sie die Methode .valid? für das Modell aufrufen, werden die Fehler in das @person-Objekt eingefügt. Daraus folgt,

Siehe

<%if @person.errors.any? %>
     <%@person.errors.messages.each do|msg| %>
          <div class="alert alert-danger">
            <%=msg[0][1]%>
          </div>
     <%end%>
<%end%>

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X