« Previous -
Version 73/76
(diff) -
Next » -
Current version
Guillermo Gómez, 04/09/2012 11:38 am
ActiveRecord validaciones¶
- ActiveRecord validaciones
- Ayudantes para validación
- Opciones comunes de validación
- Realizando validaciones personalizadas
- Trabajando con los errores de validación
- Algunos screencasts que he subido
¿Cúando ocurren las validaciones?¶
Hay dos tipos de objetos Active Records, aquellos que corresponden a una fila dentro de la base de datos y aquellos que no. Cuando se crea un objeto fresco, por ejemplo usando el método new, dicho objeto no pertenece a la base de datos aún. Una vez que llame al método save, entonces será salvado apropiadamente en la base de datos en su respectiva tabla. Active Record usa el método de instancia new_record? para determinar si un objeto ya se encuentra en la base de datos o no.
El crear y salvar un nuevo registro ejecutará una operaciń SQL INSERT en la base de datos. Actualizar un registro existente ejecutará una operación SQL UPDATE.
Las validaciones son típicamente ejecutadas antes que dichos comandos sean enviados a la base de datos. Si cualquier validación falla, el objeto será marcado como inválido y Active Record no realizará la operación INSERT o UPDATE correspondiente. Esto evita almacenar objetos inválidos en la base de datos. Usted puede escoger el tener validaciones específicas a ser ejecutadas cuando el objeto es creado, salvado o actualizado.
Existen muchas formas de cambiar el estado de un objeto en la base de datos, algunos métodos disparan las validaciones, pero algunos no. Esto significa que es posible salvar un objeto en la base de datos en un estado inválido si usted no tiene cuidado.
Los siguientes métodos activan las validaciones y salvarán el objeto en la base de datos sólo si el objeto es válido:
- create
- create!
- save
- save!
- update
- update_attributes
- update_attributes!
Un ejemplo simple.
1class Persona < ActiveRecord::Base
2end
>> p = Persona.new
#<Persona id: nil, nombres: nil, apellidos: nil, cedula: nil, correo: nil, cargo: nil, created_at: nil, updated_at: nil>
>> p.new_record?
true
>> p.save
true
>> p.new_record?
false
Evitando las validaciones¶
Los siguientes métodos evitan las validaciones y salvarán el objeto en la base de datos sin importar su validez. Deben ser utilizados con precaución.
- decrement!
- decrement_counter
- increment!
- increment_counter
- toggle!
- touch
- update_all
- update_attribute
- update_column
- update_counters
Note que save también tiene la habilidad de evitar las validaciones si se le pasa el argumento :validate => false. Esta técnica igualmente debe usarse con cuidado.
save(:validate => false)
valid? e invalid?¶
Para verificar si un objeto es válido o no, Rails usa el método valid?. También usted puede usarlo libremente. valid? activa las validaciones y devuelve true si no hay errores en el objeto, y false de cualquier otra forma.
1class Persona < ActiveRecord::Base
2 validates :nombres, :presence => true
3end
>> Persona.create(:nombres => "Juan Bimba").valid?
true
>> Persona.create(:nombres => "").valid?
false
Después de que Active Record ha ejecutado las validaciones, cualquier error encontrado estará disponible por medio del método de instancia errors que devuelve una conjunto de errores. Por definición un objeto es válido si dicho conjunto está vacío después de ejecutar las validaciones.
Note que un objeto instanciado con new no reportará errores incluso si técnicamente es inválido porque las validaciones no se ejecutando cuando se usa new.
>> p = Persona.new
#<Persona id: nil, nombres: nil, apellidos: nil, cedula: nil, correo: nil, cargo: nil, created_at: nil, updated_at: nil>
>> p.errors
#<ActiveModel::Errors:0xb3742594 @messages=#<OrderedHash {}>, @base=#<Persona id: nil, nombres: nil, apellidos: nil, cedula: nil, correo: nil, cargo: nil, created_at: nil, updated_at: nil>>
>> p.valid?
false
>> p.errors
#<ActiveModel::Errors:0xb3742594 @messages=#<OrderedHash {:nombres=>["can't be blank"]}>, @base=#<Persona id: nil, nombres: nil, apellidos: nil, cedula: nil, correo: nil, cargo: nil, created_at: nil, updated_at: nil>>
>> p.save
false
>> p.save!
ActiveRecord::RecordInvalid: Validation failed: Nombres can't be blank
>> Persona.create!
ActiveRecord::RecordInvalid: Validation failed: Nombres can't be blank
invalid? es simplemente el inverso de valid?. invalid? activa sus validaciones devolviendo true si se consiguen errores y false si no.
errors[]¶
Para verificar si un atributo en particular es válido o no, usted puede usar errors[:atributo]. Ello le devuelve un arreglo de todos los errores para :atributo. Si no hay errores para el atributo especificado, se devuelve un arreglo vacío.
Este método sólo es útil después de ejecutar las validaciones ya que se inspecciona la colección errors y no dispara las validaciones él mismo. Es diferente del método ActiveRecord::Base#invalid? porque no verifica la validez del objeto como un todo. Sólo verifica si hay errores sobre un atributo individual del objeto.
1class Persona < ActiveRecord::Base
2 validates :nombres, :presence => true
3end
>> Persona.create.errors[:nombres]
["can't be blank"]
>> Persona.create.errors[:nombres].any?
true
Trabajaremos más acerca de los errores de validación más adelaten por ahora enfoquemos en los ayudantes incluídos por Rails para validación por omisión.
Ayudantes para validación¶
Active Record ofrece muchos ayudantes predefinidos para validación que puede usar directamente dentro de las definiciones de clase. Dichos ayudantes proveen reglas comunes de validación. Cada vez que una validación falla, se agrega un mensaje de error a la colección errors del objeto y dicho mensaje es asociado con el atributo que se está validando.
Cada ayudanete acepta un número arbitrario de nombres de atributos así que en una única línea de código usted puede agregar el mismo tipo de validación para varios atributos.
Todos estos ayudantes para validación aceptan las opciones :on y :message que definen cuándo ejecutar la validación y cuál mensaje agregar a la colección errors si falla. La opción :on toma uno de los valores :save (por omisión), :create o :update. Hay un mensaje de error por omisión para cada uno de los ayudantes. Dichos mensajes son utilizados cuando no se especifica la opción :message.
A continuación algunos de los ayudantes de validación más comunes.
acceptance¶
Valida que un checkbox en la interfase del usaurio ha sido marcada cuando se envió el formulario. Esto es típicamente utilizado cuando el usuario necesita haber aceptado los términos de uso de su aplicación, confirmar haber leído un texto, o cualquier otro concepto similar. Esta validación es muy específica a las aplicaciones web y esta aceptación no necesita ser registrada en su base de datos (si usted no tiene un campo para ello, el ayudante simplemente crea un atributo virtual).
1class Persona < ActiveRecord::Base
2 validates :condiciones_del_servicio, :acceptance => true
3end
El mensaje por omisión para este ayudante es “must be accepted”.
Puede recibir la opción :accept que determina el valor que será considerado como aceptación. Por omisión es "1" y puede ser fácilmente ajustado.
1class Persona < ActiveRecord::Base
2 validates :condiciones_del_servicio, :acceptance => { :accept => 'si' }
3end
validates_associated¶
Usted debería usar este ayudante cuando su modelo tiene asociaciones con otros modelos que también necesitan ser validados. Cuando intenta salvar el objeto, valid? será llamado sobre cada uno de los modelos asociados..
1class Libreria < ActiveRecord::Base
2 has_many :libros
3 validates_associated :libros
4end
Esta validación funcionará con todos los tipos de asociaciones.
No use validates_associated en ambos extremos de la asociación. Ellos pueden llamarse mutuamente y causar un lazo infinito.
El mensaje de error por omisión es "is invalid". Note que cada objeto asociado contrendrá su propia colección errors, errors no inflan al modelo que llama.
confirmation¶
Usted debería usar este ayudante cuando tenga dos campos de texto que deban tener exactamente el mismo contenido. Por ejemplo, puede que quiera confirmar una dirección email o una contraseña. Esta validación crea un atributo virtual cuyo nombre es el nombre del campo a confirma con el sufijo "_confirmation" agregado.
1class Persona < ActiveRecord::Base
2 validates :email, :confirmation => true
3end
En su plantilla de vista podría usar algo como:
1<%= text_field :persona, :email %>
2<%= text_field :persona, :email_confirmation %>
Esta verificación se realiza sólo si email_confirmation es no nil. Para requirir información, asegúrese de agregar la verificación de presencia para el atributo a confirmar.
1class Persona < ActiveRecord::Base
2 validates :email, :confirmation => true
3 validates :email_confirmation, :presence => true
4end
El mensaje de error por omisión para este ayudante es "doesn’t match confirmation".
exclusion¶
Este ayudanete valida los valores de los atributos por si no están incluídos en un conjunto dado. De hecho dicho conjunto puede ser cualquier objeto enumerable.
1class Cuenta < ActiveRecord::Base
2 validates :subdominio, :exclusion => { :in => %w(www ve us ca jp),
3 :message => "Subdominio %{value} está reservado." }
4end
El ayudante exclusion tiene una opción :in que recibe el conjunto de valores que no serán aceptados para los atributos validados. La opción :in tiene el alias :within que puede usar para el mismo propósito si lo desea. Este ejemplo usa la opción :message para mostrar como puede incluir el valor del atributo.
El valor de error por omisión es "is reserved".
format¶
Este ayudante valida los valores de atributos probando si concuerdan con una expresión regular dada que se especifica con la opción :with.
1class Producto < ActiveRecord::Base
2 validates :codigo_heredado, :format => { :with => /\A[a-zA-Z]+\z/,
3 :message => "Sólo se permiten cartas" }
4end
El mensaje de error por omisión es "is invalid".
inclusion¶
Este ayudante valida que los valores de los atributos estén dentro de un conjunto dado. De hecho el conjunto puede ser cualquier objeto enumerable.
1class Cafe < ActiveRecord::Base
2 validates :size, :inclusion => { :in => %w(corto mediano grande),
3 :message => "%{value} no es un tamaño válido" }
4end
El ayudante de validación inclusion tiene la opción :in que recibe el conjunto de valores que serán aceptables. La opción :in tiene el alias :within que puede usar para el mismo propósito. El ejemplo previo usa la opción :message para mostrar cómo incluir el valor del atributo.
El mensaje de error por omisión es "is not included in the list".
length¶
Este ayudante valida la longitud de los valores de los atributos. Tiene una serie de opciones así que puede especificar las limitaciones de longitud de diferentes maneras
1class Persona < ActiveRecord::Base
2 validates :nombres, :length => { :minimum => 2 }
3 validates :bio, :length => { :maximum => 500 }
4 validates :password, :length => { :in => 6..20 }
5 validates :numero_de_registro, :length => { :is => 6 }
6end
Las posibles limitaciones en length son:
- :minimum – El atributo no puede tener menos de la cantidad especificada.
- :maximum – El atributo no puede tener más de la cantidad especificada.
- :in (o :within) – La longitud del atributo debe estar incluída en el intervalo dado. El valor para esta opción debe ser un rango.
- :is – La longitud del atributo debe ser igual al valor dado.
El mensaje de error por omisión depende del tipo de validación de longitud se haya probadoa. Usted puede personalziar dichos mensajes utilizando las opciones :wrong_length, :too_long, y :too_short options y el contenedor %{count} para identificar la cantidad correspondiente en uso. También puede usar la opción :message para especificar el mensaje de error.
1class Persona < ActiveRecord::Base
2 validates :bio, :length => { :maximum => 1000,
3 :too_long => "%{count} caracteres es el máximo permitido" }
4end
Este ayudante cuenta caracteres por omisión, pero puede dividir el valor en formas diferentes usando la opción :tokenizer.
1class Ensayo < ActiveRecord::Base
2 validates :contenido, :length => {
3 :minimum => 300,
4 :maximum => 400,
5 :tokenizer => lambda { |str| str.scan(/\w+/) },
6 :too_short => "debe tener al menos %{count} palabras",
7 :too_long => "debe tener máximo %{count} palabras"
8 }
9end
Note que el mensaje de error por omisión es plural (e.g., “is too short (minimum is %{count} characters)”). Por esta razón cuando :minimum es 1 usted debería proveer un mensaje personalizado o usar a cambio validates_presence_of. Cuando :in o :within tiene un límite menor a 1, usted debería proveer un mensaje personalizado o llamar presence antes de a length.
El ayudante size es un alias para length.
numericality¶
Este ayudante valida que los atributos sólo tengan valores numéricos. Por omisión concordará con un signo opcional seguido de un entero o número de punto flotante. Para especificar que sólo se permiten números enteros, use la :only_integer puesta a true.
Si pone :only_interger en true, entonces se utilizará la expresión regular:
/\A[+-]?\d+\Z/
para validar el valor del atributo. Si no es así, intentará convertir el valor a número usando Float. Note que la expresión regular permite el caracter nueva líena al final.
1class Jugador < ActiveRecord::Base
2 validates :puntos, :numericality => true
3 validates :juegos_jugados, :numericality => { :only_integer => true }
4end
Además de :only_integer este ayudante también acepta las siguientes opciones para agregar limitaciones a los valores aceptables:
- :greater_than – Especifica que el valor debe ser mayor al valor dado. El mensaje de error por omisión es "must be greater than %{count}".
- :greater_than_or_equal_to – Especifica que el valor debe ser mayor o igual que al valor dado. El mensaje de error por omisión es "must be greater than or equal to %{count}”.
- :equal_to – Especifica que el valor debe ser igual al valor dado. El mensaje de error por omisiń es "must be equal to %{count}".
- :less_than – Especifica que el valor debe ser menor que el valor dado. El mensaje de error por omisión es "must be less than %{count}".
- :less_than_or_equal_to – Especifica que el valor debe ser menor o igual que el valor dado. El mensaje de error por omisión es "must be * less than or equal to %{count}".
- :odd – Especifica que el valor debe ser un valor impar si está puesta en true. El mensaje de error por omisión es "must be odd".
- :even – Esepcifica que el valor debe ser un valor par si está puesta en true. El mensaje de error por omisión es "must be even".
El mensaje de error por omisión es "is not a number".
presence¶
Este ayudante valida que los atributos especificados no estén vacíos. Usa el método blank? para verificar el valor, ya sea nil o un string en blanco, es decir, vacío o que tenga espacios.
1class Persona < ActiveRecord::Base
2 validates :nombre, :login, :email, :presence => true
3end
Si desea asegurarse que una asociación está presente, deberá probar que la llave foránea está presente y no el objeto mismo asociado.
1class Item < ActiveRecord::Base
2 belongs_to :orden
3 validates :orden_id, :presence => true
4end
Ya que false.blank? es true, si desea validar la presencia de un campo booleano usted debería usar validates :field_name, :inclusion => { :in => [true, false] }.
El mensaje de error por omisión es "can’t be empty".
uniqueness¶
Este ayudante valida que el valor del atributo es único justo antes de que el objeto sea salvado. No crea una limitación de ser único en la base de datos así que puede pasar que dos conexiones diferentes cree dos registros con el mismo valor. Para evitar eso, usted debe crear un índice único en su base de datos.
1class Cuenta < ActiveRecord::Base
2 validates :email, :uniqueness => true
3end
Esta validación ocurre con la ejecución de una consulta SQL en la tabla del modelo, buscando algún registro existente con el mismo valor en dicho atributo.
Existe la opción :scope que puede usar para especificar otros atributos a usar para limitar la verificación de ser único:
1class Feriado < ActiveRecord::Base
2 validates :nombre, :uniqueness => { :scope => :year,
3 :message => "debe ocurrir una vez por año" }
4end
Existe también la opción :case_sensitive que puede usar para definir si la limitación es sensible al mayusculado o no. Esta opción es por omisión true.
1class Persona < ActiveRecord::Base
2 validates :nombre, :uniqueness => { :case_sensitive => false }
3end
Note que algunas bases de datos son configuradas para realizar búsquedas insensibles al mayusculados de todas maneras.
El mensaje de error por omisión es "has already been taken".
validates_with¶
Este ayudante pasa el registro a una clase aparte para validación.
1class Persona < ActiveRecord::Base
2 validates_with BondadValidador
3end
4
5class BondadValidador < ActiveModel::Validator
6 def validate(record)
7 if record.primer_nombre == "Diablo"
8 record.errors[:base] << "Esta persona es malvada"
9 end
10 end
11end
Los errores agregados a record.errors[:base] relaciona el estado del registro como un todo y no a un atributo específico.
El ayudante validates_with toma una clase o una lista de clases para validación. No hay mensaje de error por omisión para validates_with. Usted debe manualmente agregar los errores a los errores de la colección en la clase validadora.
Para implementar el método validate usted debe tener definido un parámetro record que es el registro a validar.
Como todas las otras validaciones validate_with tiene las opciones :if, :unless y :on. Si usted pasa cualquier otra opción, se pasarán dichas opciones a la clase validadora como opciones.
1class Persona < ActiveRecord::Base
2 validates_with BondadValidador, :fields => [:primer_nombre, :apellido]
3end
4
5class BondadValidador < ActiveModel::Validator
6 def validate(record)
7 if options[:fields].any?{|field| record.send(field) == "Diablo" }
8 record.errors[:base] << "Esta persona es malvada"
9 end
10 end
11end
validates_each¶
Este ayudante valida atributos con un bloque. No tiene una función predefinida de validación. Usted debe crear dicha función de validación utilizando un bloque y cada atributo pasado a validates_each será probado usando dicho bloque. En el siguiente ejemplo no queremos nombres y apellidos que comiencen con una minúscula.
1class Persona < ActiveRecord::Base
2 validates_each :nombre, :apellido do |record, attr, value|
3 record.errors.add(attr, 'debe comenzar con mayúscula') if value =~ /\A[a-z]/
4 end
5end
El bloque recibe el registro, el nombre del atributo y el valor del atributo. Usted es libre de hacer lo que quiera para verificar la validez de los datos dentro del bloque. Si su validación falla, usted debería agregar un mensaje de error al modelo haciéndolo entonces inválido.
Opciones comunes de validación¶
Las siguientes son opciones comunes de validación.
:allow_nil¶
La opción :allow_nil evita la validación cuando el valor validado es nil.
1class Cafe < ActiveRecord::Base
2 validates :size, :inclusion => { :in => %w(corto mediano grande),
3 :message => "%{value} no es un tamaño válido" }, :allow_nil => true
4end
:allow_nil es ignorado por el validador presence.
:allow_blank¶
La opción :allow_blank es similar a la opción :allow_nil. Esta opción permitirá que pase la validación si el valor del atributoes blank?, como nil o un string vacío por ejemplo.
1class Tema < ActiveRecord::Base
2 validates :titulo, :length => { :is => 5 }, :allow_blank => true
3end
Tema.create("titulo" => "").valid? # => true
Tema.create("titulo" => nil).valid? # => true
:allow_blank es ingnorado por el validador presence.
:message¶
Como ya se ha visto previamente, la opción :message permite especificar el mensaje que será agregado a la colección errors cuando la validación falla. Cuando no se usa esta opción, Active Record usará el mensaje de error por omisión respectivo para ayudante de validación.
:on¶
La opción :on permite especificar cuando debe ocurrir la validación. El comportamiento por omisión para todos los ayudantes de validación integrados es ser ejecutados al salvar, tanto al crear un nuevo registro y cuando lo esté actualizando. Si desea cambiar este comportamiento puede usar :on => :create para ejecutar la validación sólo cuando se cree un nuevo registro o :on => :update para ejecutar la validación sólo cuando se actualice el registro.
1class Persona < ActiveRecord::Base
2 # será posible actualizar email con valor duplicado
3 validates :email, :uniqueness => true, :on => :create
4
5 # será posible crear un registro con edad no numérico
6 validates :edad, :numericality => true, :on => :update
7
8 # por omisión (valida, tanto en create como en update)
9 validates :nombre, :presence => true, :on => :save
10end
Validación condicional¶
Algunas veces tendrá sentido validar un objeto sólo cuando cierto predicado sea satisfecho. Usted puede lograr este comportamiento usando las opciones :if y :unless que toman un símbolo, un string o un Proc. Usted puede usar la opción :if cuando desee especificar cuando debe ocurrir la validación. Si desea especificar cuando la validación no deba ocurrir, entonces puede usar la opción :unless.
Uso de un Symbol con :if y :unless¶
Usted puede asociar las opciones :if y :unless con un Symbol correspondiente al nombre de un método que será llamado justo antes de que ocurra la validación. Esta es la opción más comúnmente utilizada.
1class Orden < ActiveRecord::Base
2 validates :numero_de_tarjeta, :presence => true, :if => :pagado_con_tarjeta?
3
4 def pagado_con_tarjeta?
5 tipo_de_pago == "tarjeta"
6 end
7end
Uso de un String con :if y :unless¶
También se puede usar un String que será evaluado utilizando eval y que debe contener código Ruby válido. Usted debe usar estar opción sólo cuando el string representa un condición corta.
1class Persona < ActiveRecord::Base
2 validates :apellido, :presence => true, :if => "nombre.nil?"
3end
Uso de Proc con :if y :unless¶
Finalmente es posible asociar :if y :unless con un objeto Proc que será llamado. Usando un objeto Proc le ofrece la habilidad de escribir una condición en línea en vez de separada en un método. Esta opción se usar mejor como los llamados one-liners.
1class Cuenta < ActiveRecord::Base
2 validates :password, :confirmation => true,
3 :unless => Proc.new { |a| a.password.blank? }
4end
Agrupando validaciones condicionales¶
Algunas veces es útil tener múltiples validaciones que usan una condición, ello se puede lograr fácilmente con el uso de with_options.
1class Usuario < ActiveRecord::Base
2 with_options :if => :es_admin? do |admin|
3 admin.validates :password, :length => { :minimum => 10 }
4 admin.validates :email, :presence => true
5 end
6end
Todas las validaciones dentro del bloque with_options les será pasado automáticamente la condición :if => :es_admin?
Realizando validaciones personalizadas¶
Cuando los ayudantes integrados de validación no son suficiente para cubrir sus necesidades, usted puede escribir sus propios validadores o métodos de validación.
Validadores personalizados¶
Los validadores personalizados son clases que extienden ActiveModel::Validator. Dichas clases implementan un método validate que toma un registro como argumento y realiza la validación sobre él. El validador personalizado es llamado utilizando el método validates_with.
1class MiValidador < ActiveModel::Validator
2 def validate(record)
3 unless record.nombre.starts_with? 'X'
4 record.errors[:nombre] << '¡Necesita un nombre que comience con X por favor!'
5 end
6 end
7end
8
9class Persona
10 include ActiveModel::Validations
11 validates_with MiValidador
12end
La manera más fácil de agregar validadores personalizados para validar atributos individuales es con el conveniente ActiveModel::EachValidator. En ese caso la clase del validador personalizado debe implementar el método validate_each que tome tres argumentos: registro, atributo y valor que corresponden a la instancia, el atributo a validar y el valor del atributo en la instancia.
1class EmailValidador < ActiveModel::EachValidator
2 def validate_each(record, attribute, value)
3 unless value =~ /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
4 record.errors[attribute] << (options[:message] || "no es un email")
5 end
6 end
7end
8
9class Persona < ActiveRecord::Base
10 validates :email, :presence => true, :email => true
11end
Como se muestra en el ejemplo, se pueden combinar las validaciones estandar con las personalizadas..
Métodos personalizados¶
También puede crear métodos que verifiquen el estado de sus modelos y agregar mensages a la colección errors cuando son inválidos. Uste debe entonces registrar dichos métodos utilizando el método de clase validate pasando en los símbolo los nombres de los métodos de validación.
Usted puede pasar más de un símbolo para cada método de clase y las respectivas validaciones serán ejecutadas en el mismo orden que fueron registradas.
1class Factura < ActiveRecord::Base
2 validate :fecha_de_vencimiento_no_puede_estar_en_el_pasado,
3 :descuento_no_puede_ser_mayor_que_el_valor_total
4
5 def fecha_de_vencimiento_no_puede_estar_en_el_pasado
6 if !fecha_de_vencimiento.blank? and fecha_de_vencimiento < Date.today
7 errors.add(:fecha_de_vencimiento, "no puede estar en el pasado")
8 end
9 end
10
11 def descuento_no_puede_ser_mayor_que_el_valor_total
12 if descuento > valor_total
13 errors.add(:descuento, "no puede ser mayor que el valor total")
14 end
15 end
16end
Por omisión tales validaciones serán ejecutadas cada vez que llame a valid? También es posible controlar cuándo ejecutar las validaciones personalizadas especificando la opción :on en el método validate para que sea :create o :update.
1class Factura < ActiveRecord::Base
2 validate :cliente_activo, :on => :create
3
4 def cliente_activo
5 errors.add(:cliente_id, "no está activo") unless cliente.active?
6 end
7end
También puede crear sus propios ayudantes de validación y reusarlos en diferentes modelos. Por ejemplo, una aplicación que gestione encuestas puede que necesite expresar que cierto campo corresponde con un conjunto de elecciones:
1ActiveRecord::Base.class_eval do
2 def self.valida_como_escogencia(attr_name, n, options={})
3 validates attr_name, :inclusion => { { :in => 1..n }.merge!(options) }
4 end
5end
Simplemente reabra ActiveRecord::Base y defina un método de clase como ese. Típicamente usted pondría ese código en alguna parte en config/initializers. Entonces podría usar dicho ayudante así:
1class Movie < ActiveRecord::Base
2 valida_como_escogencia :valoracion, 5
3end
Trabajando con los errores de validación¶
Además de los métodos valid? e invalid? cubiertos anteriormente, Rails suministra una cantidad de métodos para trabajar con la colección errors y para preguntar acerca de la validez de los objetos.
La siguiente es una lista de los métodos más comunes. Por favor refiérase a la documentación de ActiveModel::Errors para obtener la lista completa.
errors¶
Devuelve una instancia de la clase ActiveModel::Errors, que se comporta como un hash ordenado conteniendo todos los errores. Cada llave es un nombre de atributo y el valor es un arreglo de strings con todos los errores.
1class Persona < ActiveRecord::Base
2 validates :nombre, :presence => true, :length => { :minimum => 3 }
3end
persona = Persona.new
persona.valid? # => false
persona.errors
# => {:nombre => ["can't be blank", "is too short (minimum is 3 characters)"]}
persona = Persona.new(:nombre => "Juan Bimba")
persona.valid? # => true
persona.errors # => []
errors[]¶
errors[] se usa cuando desea verificar mensajes de error para un atributo específico. Devuelve un arreglo de strings con todos los mensajes de error para el atributo dado, cada string con un mensaje de error. Si no hay errores relacionados al atributo, devuelve un arreglo vacío.
1class Persona < ActiveRecord::Base
2 validates :nombre, :presence => true, :length => { :minimum => 3 }
3end
persona = Persona.new(:nombre => "Juan Bimba") persona.valid? # => true persona.errors[:nombre] # => [] persona = Persona.new(:nombre => "JB") persona.valid? # => false persona.errors[:nombre] # => ["is too short (minimum is 3 characters)"] persona = Persona.new persona.valid? # => false persona.errors[:nombre] # => ["can't be blank", "is too short (minimum is 3 characters)"]
errors.add¶
El método add le permite manualmente agregar mensajes de error relacionados a un atributo particular. Puede usar los métodos errors.full_messages o errors.to_a methods para ver los mensajes en la forma que pueda ser mostrados al usuario. Estos mensajes en particular obtienen el nombre de atributo prefijado y mayúsculado. add recibe el nombre de atributo al cual usted desea agregar el mensaje y el mensaje mismo.
1class Persona < ActiveRecord::Base
2 def metodo_para_validacion
3 errors.add(:nombre, "no puede tener los caracteres !@#%*()_-+=")
4 end
5end
persona = Persona.create(:nombre => "!@#") person.errors[:nombre] # => ["no puede tener los caracteres !@#%*()_-+="] person.errors.full_messages # => ["Nombre no puede tener los caracteres !@#%*()_-+="]
Otra forma de lograr este comportamiento es usando un setter []=.
1class Persona < ActiveRecord::Base
2 def metodo_para_validacion
3 errors[:name] = "no puede tener los caracteres !@#%*()_-+="
4 end
5end
persona = Persona.create(:nombre => "!@#") persona.errors[:nombre] # => ["no puede tener los caracteres !@#%*()_-+="] persona.errors.to_a # => ["Nombre no puede tener los caracteres !@#%*()_-+="]
errors[:base]¶
Usted puede agregar mensajes de error relacionados al estado del objeto como un todo en vez de relacionarlo a un atributo específico. Puede usar este método cuando lo que quiere decir es que el objeto es inválido sin importar qué valores tengan sus atributos. Ya que errors[:base] es un arreglo, usted puede simplemente agregar un string y éste será usado como mensaje de error.
1class Persona < ActiveRecord::Base
2 def metodo_para_validacion
3 errors[:base] << "Esta persona es no válida porque..."
4 end
errors.clear¶
El método clear se usa cuando intencionalmente se desea limpiar todos los mensajes en la colección errors. Por supuesto el llamar errors.clear sobre un objeto inválido no lo hace válido: la colección errors ahora estará vacía pero la próxima vez que llame a valid? o cualquier otro método que intente salvar el objeto a la base de datos, las validaciones serán ejecutadas nuevamente. Si cualquier validación falla, la colección errors será rellenado nuevamente.
1class Persona < ActiveRecord::Base
2 validates :nombre, :presence => true, :length => { :minimum => 3 }
3end
persona = Persona.new persona.valid? # => false persona.errors[:nombre] # => ["can't be blank", "is too short (minimum is 3 characters)"] persona.errors.clear persona.errors.empty? # => true persona.save # => false persona.errors[:nombre] # => ["can't be blank", "is too short (minimum is 3 characters)"]
errors.size¶
El método size devuelve la cantidad total de mensajes de error para el objeto.
1class Persona < ActiveRecord::Base
2 validates :nombre, :presence => true, :length => { :minimum => 3 }
3end
persona = Persona.new persona.valid? # => false persona.errors.size # => 2 persona = Persona.new(:nombre => "Andrea", :email => "andrea@ejemplo.com") persona.valid? # => true persona.errors.size # => 0
