Ich habe eine Rails-App, mit der ein Benutzer eine Datenbankabfrage erstellen kann, indem er ein umfangreiches Formular ausfüllt. Ich wunderte mich über die bewährte Methode zum Überprüfen von Formularparametern in Rails. Zuvor hatte ich mit meiner results
-Methode (der Methode, an die das Formular übermittelt wird) Folgendes ausgeführt:
if params[:name] && !params[:name].blank?
@name = params[:name]
else
flash[:error] = 'You must give a name'
redirect_to :action => 'index'
return
end
Aber für mehrere Formularfelder wurde es langweilig, wenn man dies für jedes Formular wiederholt sah. Ich konnte sie nicht einfach in eine Schleife stecken, um jedes Feld zu überprüfen, da die Felder unterschiedlich eingerichtet sind:
params[:name]
params[:image][:font_size]
Dies wiederholte sich auch, da ich flash[:error]
für jeden fehlenden/ungültigen Parameter einrichtete und für jeden Parameter die gleiche URL umleitete. Ich wechselte zu einem before_filter
, der alle notwendigen Formularparameter prüft und nur dann true zurückgibt, wenn alles in Ordnung ist. Dann fährt die my results
-Methode fort, und die Variablen werden einfach platt zugewiesen, ohne dass eine Überprüfung erforderlich ist:
@name = params[:name]
In meiner validate_form
-Methode habe ich folgende Codeabschnitte:
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 habe mich nur gefragt, ob ich das am besten mache oder ob mir bei der Validierung von Parametern etwas offensichtliches fehlt. Ich mache mir Sorgen, dass dies immer noch nicht die effizienteste Technik ist, da ich mehrere Blöcke habe, in denen ich flash[:error]
einen Wert zuweise, dann auf dieselbe URL umleite und dann false zurückgibt.
Bearbeiten, um zu klären: Der Grund, warum ich diese Validierung in Modellen derzeit nicht habe, hat zwei Gründe:
Bearbeiten, um die verbesserte Technik anzuzeigen: Ich verwende jetzt anwendungsspezifische Ausnahmen, dank Jamis Buck's Raising the Right Exception-Artikel . 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
Sie könnten active_form versuchen ( http://github.com/cs/active_form/tree/master/lib/active_form.rb) - Nur ActiveRecord minus Datenbankmaterial. Auf diese Weise können Sie das gesamte Validierungsmaterial von AR verwenden und Ihr Formular wie jedes andere Modell behandeln.
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
Sieht so aus, als würden Sie die Validierung im Controller durchführen, versuchen Sie es in das Modell einzufügen, es ist besser für solche Dinge geeignet.
Wenn Sie das Problem heute noch einmal angehen würden, könnten Sie ein Modell für den Abfrageparametersatz erstellen und die integrierten Validierungen von Rails verwenden. Rails 3 macht dies mit ActiveModel :: Validations viel einfacher - siehe this post .
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 zur Validierung nicht unbedingt speichern oder beibehalten müssen.
@person.name= params["name"]
@person.email= params["email"]
@person.valid?
Eine, die Sie angerufen haben. Wenn Sie die Methode des Modells verwenden, werden die Fehler in einem @person-Objekt angezeigt. Daher,
<%if @person.errors.any? %>
<%@person.errors.messages.each do|msg| %>
<div class="alert alert-danger">
<%=msg[0][1]%>
</div>
<%end%>
<%end%>