validator validations validates_presence_of validates validate rails method custom create ruby-on-rails ruby-on-rails-3 validation activemodel

ruby on rails - validations - Controlar el orden de validaciones de rieles



rails validates if (4)

Tengo un modelo de rieles que tiene 7 atributos numéricos completados por el usuario a través de un formulario.

Necesito validar la presencia de cada uno de estos atributos, que obviamente es fácil de usar

validates :attribute1, :presence => true validates :attribute2, :presence => true # and so on through the attributes

Sin embargo, también necesito ejecutar un validador personalizado que tome varios atributos y haga algunos cálculos con ellos. Si el resultado de estos cálculos no está dentro de un cierto rango, entonces el modelo debe declararse no válido.

Por sí mismo, esto también es fácil

validate :calculations_ok? def calculations_ok? errors[:base] << "Not within required range" unless within_required_range? end def within_required_range? # check the calculations and return true or false here end

Sin embargo, el problema es que el método "validar" siempre se ejecuta antes de que el método "valide". Esto significa que si el usuario deja en blanco uno de los campos obligatorios, Rails arroja un error cuando intenta hacer un cálculo con un atributo en blanco.

Entonces, ¿cómo puedo verificar primero la presencia de todos los atributos requeridos?



La solución James H tiene más sentido para mí. Una cosa más a tener en cuenta, sin embargo, es que si tiene condiciones en las validaciones dependientes, también deben verificarse para el atributo dependiente_valido. llamar al trabajo.

es decir.

validates :attribute1, presence: true validates :attribute1, uniqueness: true, if: :attribute1? validates :attribute1, numericality: true, unless: Proc.new {|r| r.attribute1.index("@") } validates :attribute2, presence: true ... validates :attribute7, presence: true validate :calculations_ok?, unless: Proc.new { |a| a.dependent_attributes_valid? } def dependent_attributes_valid? [:attribute1, ..., :attribute7].each do |field| self.class.validators_on(field).each do |v| # Surely there is a better way with rails? existing_error = v.attributes.select{|a| self.errors[a].present? }.present? if_condition = v.options[:if] validation_if_condition_passes = if_condition.blank? validation_if_condition_passes ||= if_condition.class == Proc ? if_condition.call(self) : !!self.send(if_condition) unless_condition = v.options[:unless] validation_unless_condition_passes = unless_condition.blank? validation_unless_condition_passes ||= unless_condition.class == Proc ? unless_condition.call(self) : !!self.send(unless_condition) if !existing_error and validation_if_condition_passes and validation_unless_condition_passes v.validate(self) end end return false if self.errors.messages[field].present? end return true end


No estoy seguro de que esté garantizado en qué orden se ejecutan estas validaciones, ya que podría depender de cómo termine ordenado el propio hash de attributes . Tal vez sea mejor que su método de validate más resistente y simplemente no se ejecute si falta alguno de los datos requeridos. Por ejemplo:

def within_required_range? return if ([ a, b, c, d ].find(&:blank?)) # ... end

Esto se rescatará si cualquiera de las variables a hasta d está en blanco, lo que incluye nil, matrices vacías o cadenas, y así sucesivamente.


Una alternativa para situaciones ligeramente más complejas sería crear un método auxiliar que ejecute primero las validaciones para los atributos dependientes. Entonces puedes hacer tu: calculations_ok? la validación se ejecuta condicionalmente.

validates :attribute1, :presence => true validates :attribute2, :presence => true ... validates :attribute7, :presence => true validate :calculations_ok?, :unless => Proc.new { |a| a.dependent_attributes_valid? } def dependent_attributes_valid? [:attribute1, ..., :attribute7].each do |field| self.class.validators_on(field).each { |v| v.validate(self) } return false if self.errors.messages[field].present? end return true end

Tuve que crear algo como esto para un proyecto porque las validaciones en los atributos dependientes eran bastante complejas. Mi equivalente de: calculations_ok? lanzaría una excepción si los atributos dependientes no validarían correctamente.

Ventajas:

  • relativamente seco, especialmente si sus validaciones son complejas
  • asegura que su matriz de errores informe la correcta validación fallida en lugar de la macrovalidación
  • incluye automáticamente cualquier validación adicional en los atributos dependientes que agrega más adelante

Advertencias:

  • potencialmente ejecuta todas las validaciones dos veces
  • es posible que no desee que todas las validaciones se ejecuten en los atributos dependientes