J'ai une application Rails qui permet à un utilisateur de créer une requête de base de données en remplissant un formulaire détaillé. Je me suis demandé quelle était la meilleure pratique pour vérifier les paramètres de formulaire dans Rails. Auparavant, ma méthode results
(celle à laquelle le formulaire est soumis) s’effectue comme suit:
if params[:name] && !params[:name].blank?
@name = params[:name]
else
flash[:error] = 'You must give a name'
redirect_to :action => 'index'
return
end
Mais pour plusieurs champs de formulaire, le voir répété pour chacun devenait fastidieux. Je ne pouvais pas simplement les insérer tous dans une boucle pour vérifier chaque champ, car les champs sont configurés différemment:
params[:name]
params[:image][:font_size]
Etc. Cela a également été répétitif, car je mettais flash[:error]
pour chaque paramètre manquant/invalide, et redirigeais vers la même URL pour chacun. Je suis passé à utiliser un before_filter
qui vérifie tous les paramètres de formulaire nécessaires et ne renvoie true que si tout va bien. Ensuite, la méthode my results
continue, et les variables sont simplement assignées à plat, sans vérification:
@name = params[:name]
Dans ma méthode validate_form
, j'ai des sections de code comme celles-ci:
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
Je me demandais simplement si je m'y prenais de la meilleure façon ou s'il me manquait quelque chose d'évident en ce qui concerne la validation des paramètres. Je crains que ce ne soit toujours pas la technique la plus efficace, car j'ai plusieurs blocs dans lesquels j'attribue une valeur à flash[:error]
, puis je redirige vers la même URL, puis je renvoie false.
Modifier pour clarifier: La raison pour laquelle je n’ai pas cette validation dans le (s) modèle (s) actuellement est pour deux raisons:
Éditer pour montrer une technique améliorée: J'utilise maintenant les exceptions spécifiques à une application, grâce à l'article de Jamis Buck - Raising the Right Exception . Par exemple:
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
Vous pouvez essayer active_form ( http://github.com/cs/active_form/tree/master/lib/active_form.rb) - juste ActiveRecord moins les affaires de base de données. De cette façon, vous pouvez utiliser tous les éléments de validation d'AR et traiter votre formulaire comme n'importe quel autre modèle.
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
On dirait que vous faites la validation dans le contrôleur, essayez de l'insérer dans le modèle, c'est mieux adapté à ce genre de chose.
Si vous deviez vous attaquer de nouveau au problème aujourd'hui, vous pourriez créer un modèle pour le jeu de paramètres de requête et utiliser les validations intégrées de Rails. Rails 3 simplifie grandement cette opération avec ActiveModel :: Validations voir 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
Notez que vous n'avez pas nécessairement besoin de sauvegarder/conserver le modèle pour le valider.
@person.name= params["name"]
@person.email= params["email"]
@person.valid?
Un que vous avez appelé .valid? méthode sur le modèle, les erreurs seront renseignées dans l’objet @person. Par conséquent,
<%if @person.errors.any? %>
<%@person.errors.messages.each do|msg| %>
<div class="alert alert-danger">
<%=msg[0][1]%>
</div>
<%end%>
<%end%>