2008-12-11 10 views
20

Tengo una aplicación de Rails que permite al usuario construir una consulta de base de datos completando un formulario extenso. Me pregunté cuál sería la mejor práctica para verificar los parámetros de formulario en Rails. Anteriormente, he tenido mi results método (aquella a la que se somete el formulario) hacer lo siguiente:Rails form validation

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

Pero para varios campos de formulario, al ver esto repite para cada uno de ellos tiene tedioso. No podía sólo se adhieren a todos en algún bucle para comprobar cada campo, porque los campos están configurados de manera diferente:

  • una sola tecla: params[:name]
  • una clave y un sub-clave: params[:image][:font_size]
  • sólo se esperan algunos campos de formulario para ser llenado si otro campo se establece

Etc. Esto también era repetitivo, porque yo estaba sentado flash[:error] para cada parámetro que falta/no válida, y redirigir a la misma URL para cada uno. Cambié a usar un before_filter que busca todos los parámetros de formulario necesarios y solo devuelve verdadero si todo está bien. A continuación, el mi método results continúa, y las variables se acaba de asignar de plano, sin comprobación de que se trate:

@name = params[:name] 

En mi método validate_form, tengo secciones de código como el siguiente:

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 

I Me preguntaba si estoy haciendo esto de la mejor manera, o si me falta algo obvio cuando se trata de la validación de parámetros. Me preocupa que esta no sea todavía la técnica más eficiente, porque tengo varios bloques en los que asigno un valor a flash[:error], luego los redirecciono a la misma URL y luego devuelvo falso.

Editar para aclarar: La razón por la que no tengo esta validación en el modelo (s) actualmente es por dos razones:

  • No estoy tratando de recopilar datos del usuario con el fin de crear o actualizar una fila en la base de datos. Ninguno de los datos que envía el usuario se guarda después de cerrar la sesión. Todo se usa correctamente cuando lo envían para buscar en la base de datos y generar algunas cosas.
  • El formulario de consulta toma datos pertenecientes a varios modelos y toma otros datos que no pertenecen a ningún modelo. P.ej. el tipo de gráfico y el tema que se muestran arriba no se conectan a ningún modelo, solo transmiten información sobre cómo el usuario desea mostrar sus resultados.

Editar para mostrar una técnica mejorada: que hacen uso de las excepciones específicas de la aplicación ahora, gracias a Jamis Buck Raising the Right Exception article. Por ejemplo:

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

Creo que no tiene que usar params [: nombre] y! Params [: nombre] .blank? en tus condiciones ! params [: nombre] .blank? es suficiente. params [: name] devuelve false si es nil (no hay tal parámetro) y params [: name] .blank? devuelve verdadero si es nulo o está vacío. – klew

+0

Obtiene un NoMethodError. Podría anular NilClass para agregar #blank? a eso, supongo. irb (main): 002: 0> params = {: a => 1,: b => 2,: c => 3} => {: c => 3,: a => 1,: b => 2} irb (main): 003: 0>! Params [: nombre] .blank? NoMethodError: método indefinido '¿en blanco? ' para nil: NilClass de (irb): 3 –

+0

No Ruby aquí, solo Rails. * etiqueta eliminada * – Nakilon

Respuesta

25

Puede intentar active_form (http://github.com/cs/active_form/tree/master/lib/active_form.rb) - solo ActiveRecord menos las cosas de la base de datos. De esta forma, puede usar todas las validaciones de AR y tratar su formulario como lo haría con cualquier otro modelo.

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

¿Es 'validates_presence_of: name' un alias para' validates: name, presence: true'? Solo he visto este último en las guías de Rails. – Dennis

+1

Para responder a mi propia pregunta, la última forma es una nueva forma de hacer las validaciones introducidas en Rails 3. http://thelucid.com/2010/01/08/sexy-validation-in-edge-rails-rails-3/ – Dennis

6

Parece que está haciendo la validación en el controlador, tratan de ponerlo en el modelo, que es más adecuado para ese tipo de cosas.

+4

Como se recomienda en la [guía] (http://guides.rubyonrails.org/active_record_validations_callbacks.html) también: "Las validaciones a nivel de controlador pueden ser tentadores de usar, pero a menudo se vuelven difíciles de manejar y difíciles de probar. mantener. Siempre que sea posible, es una buena idea [mantenga sus controladores delgados] (http://weblog.jamisbuck.org/2006/10/18/skinny-controller-fat-model), ya que hará que su aplicación sea un placer para trabajar a largo plazo ". –

2

Si se va a abordar el problema de nuevo hoy, se puede crear un modelo para el conjunto de parámetros de consulta y el uso de rieles construida en validaciones, Rails 3 hace esto mucho más fácil con ActiveModel :: validaciones ver this post.