validator validations validate validar rails formularios formulario form anidados ruby-on-rails ruby validation activerecord

ruby on rails - validations - ¿Hay alguna forma de validar un atributo específico en un ActiveRecord sin crear primero un objeto?



validate form rails (8)

Por ejemplo, si tengo un modelo de usuario y necesito validar solo el inicio de sesión (lo que puede suceder al validar un formulario a través de ajax), sería genial si utilizo las mismas validaciones de modelo definidas en el modelo de usuario sin crear una instancia de usuario. .

Entonces en el controlador podría escribir código como

User.valid_attribute?(:login, "login value")

¿Hay alguna forma de que pueda hacer esto?


Dado que las validaciones operan en instancias (y utilizan el atributo de errores de una instancia como un contenedor para mensajes de error), no puede usarlos sin tener el objeto instanciado. Habiendo dicho eso, puedes ocultar este comportamiento necesario en un método de clase:

class User < ActiveRecord::Base def self.valid_attribute?(attr, value) mock = self.new(attr => value) unless mock.valid? return mock.errors.has_key?(attr) end true end end

Ahora, puedes llamar

User.valid_attribute?(:login, "login value")

tal como lo pretendiste

(Idealmente, incluirías ese método de clase directamente en ActiveRecord :: Base para que esté disponible para todos los modelos).


He ido con la solución de clase personalizada, pero solo quería asegurarme de que no había una mejor manera

class ModelValidator def self.validate_atrribute(klass, attribute, value) obj = Klass.new obj.send("#{attribute}=", value) obj.valid? errors = obj.errors.on(attribute).to_a return (errors.length > 0), errors end end

y puedo usarlo como

valid, errors = ModelValidator.validate_attribute (Usuario, "inicio de sesión", "humanzz")


Para usar sus rutinas de validación estándar:

User.new(:login => ''login_value'').valid?

Si eso no funciona para usted, cree un método de clase personalizado para esto:

class User < ActiveRecord::Base validate do |user| user.errors.add(''existing'') unless User.valid_login?(user.login) end def self.valid_login?(login) # your validation here !User.exist?(:login=> login) end end


Una implementación del método ''valid_attribute'' que está sugiriendo:

class ActiveRecord:Base def self.valid_attribute?(attribute, value) instance = new instance[attribute] = value instance.valid? list_of_errors = instance.errors.instance_variable_get(''@errors'')[attribute] list_of_errors && list_of_errors.size == 0 end end


class User < ActiveRecord::Base validates_each :login do |record, attr, value| record.errors.add attr, ''error message here'' unless User.valid_login?(value) end def self.valid_login?(login) # do validation end end

Simplemente llame a User.valid_login? (Login) para ver si el inicio de sesión es válido


Qué tal si:

User.columns_hash.has_key? (''Login'')


Gracias Milan por tu sugerencia. Inspirado por él, creé un módulo simple que se puede usar para agregar esta funcionalidad a cualquier clase. Tenga en cuenta que la sugerencia original de Milans tiene un error lógico como línea:

return mock.errors.has_key?(attr)

debería ser claramente:

return (not mock.errors.has_key?(attr))

He probado mi solución y debería funcionar, pero ofc no doy ninguna garantía. Y aquí está mi gloriosa solución. Básicamente un 2-liner si quitas las cosas del módulo. Acepta nombres de métodos como aguijones o símbolos.

module SingleAttributeValidation def self.included(klass) klass.extend(ClassMethods) end module ClassMethods def valid_attribute?(attr, value) mock = self.new(attr => value) (not mock.valid?) && (not mock.errors.has_key?(attr.class == Symbol ? attr : attr.to_sym)) end end end


Me costó un montón conseguir que esto funcione en Rails 3.1. Esto finalmente funcionó. (No estoy seguro de si es la mejor manera de hacerlo, soy un poco nuevo). El problema que estaba teniendo era que ese valor se estaba configurando para que escriba ActiveSupport :: SafeBuffer, y estaba fallando la validación.

def self.valid_attribute?(attr, value) mock = User.new(attr => "#{value}") # Rails3 SafeBuffer messes up validation unless mock.valid? return (not mock.errors.messages.has_key?(attr)) end return true end