2011-08-18 9 views
6

Si tengo un modelo ActiveRecord de la siguiente maneraevaluación de la clase Ruby, validates_inclusion_of con datos dinámicos

class Foo < ActiveRecord::Base 
    validates_inclusion_of :value, :in => self.allowed_types 

    def self.allowed_types 
    # some code that returns an enumerable 
    end 
end 

Esto no funciona porque el método allowed_types no se ha definido en el momento en que se evalúa la validación. Todas las soluciones que se me ocurren básicamente giran en torno a mover la definición del método por encima de la validación para que esté disponible cuando sea necesario.

Aprecio que esto sea más una pregunta de estilo de codificación que cualquier otra cosa (quiero todas mis validaciones en la parte superior del modelo y los métodos en la parte inferior) pero creo que debería haber algún tipo de solución, posiblemente ¿implica una evaluación perezosa de la carga inicial del modelo?

es lo que quiero hacer posible? ¿Debo simplemente definir el método por encima de la validación o hay una mejor solución de validación para lograr lo que quiero?

+0

@eightbitraptor ... tratar ': en => Foo.allowed_types' en lugar de': en => self.allowed_types' ... pd Creo 'self' se hace referencia al objeto de 'Foo' en lugar de' Foo' – rubyprince

Respuesta

10

Debería poder usar la sintaxis lambda para este propósito. Tal como esto:

class Foo < ActiveRecord::Base 
    validates_inclusion_of :value, :in => lambda { |foo| foo.allowed_types } 

    def allowed_types 
    # some code that returns an enumerable 
    end 
end 

De esta manera se evaluará el bloque lambda en cada validación y pasar a la instancia de Foo al bloque. A continuación, devolverá el valor de allowed_types en esa instancia para que pueda validarse dinámicamente.

También tenga en cuenta que eliminé self. de la declaración del método allowed_types porque eso crearía un método de clase en lugar de un método de instancia que es lo que quiere aquí.

+0

gracias excelentes, eso era exactamente lo que estaba tratando de hacer con eso, simplemente no me daba cuenta de que pasar un objeto a la lambda pasaría el objeto que se valida. – eightbitraptor

+0

Ojalá pudiera votar esto dos veces. – patrickmcgraw

+1

Puede usar ': in => lambda (&: allowed_types)' para una sintaxis aún más compacta. – radiospiel

0

La opción: in del método validates_inclusion_of no parece aceptar una lambda o Proc. Aquí hay otro enfoque:

validates_each :product_id do |record, attrib, value| 
    begin 
    Product.find(value) 
    rescue ActiveRecord::ActiveRecordError 
    record.errors.add attrib, 'must be selected from list.' 
    end 
end 
Cuestiones relacionadas