2011-01-28 9 views
25

Estoy construyendo una validación personalizada que comprueba un número de cuenta y tipo de código banco con una API externa para comprobar si existen (es decir, es una cuenta de banco del Reino Unido válida apropiada) . Como esta es una operación costosa, no quiero molestarme en pulsar la API a menos que el número de cuenta y el código de clasificación pasen las validaciones integradas de Rails.lleve a cabo una validación sólo si todas las demás validaciones pasan

Por ejemplo, tengo estas validaciones básicas:

validates_presence_of :sort_code, :account_number 
validates_format_of :sort_code, :with => Regexes::SORT_CODE 
validates_format_of :account_number, :with => Regexes::ACCOUNT_NUMBER 

entonces tengo mi validación personalizada:

validate :check_valid_bank_account 

def check_valid_bank_account 
    # code here is irrelevant, but essentially this hits the API 
    # if it's a valid UK bank account all is OK, if not we add an error 
end 

Lo que quiero asegurar es que la validación personalizada sólo se realiza si el resto del modelo es válido. No tiene sentido pagar a 25p para que me digan que no me proporcionaron ningún número de cuenta cuando puedo resolverlo yo mismo.

Soy consciente de que podría escribir algo de lógica que compruebe que los dos atributos no están en blanco y los compara con la expresión regular de forma manual ... pero eso no parece una forma muy Rails.

Respuesta

26

Puede consultar la matriz errors y regresar.

def check_valid_bank_account 
    return unless errors.blank? 
    … 
end 
+1

no creo que esto va a funcionar si la validación check_valid_bank_account se ejecuta antes de que los otros validaciones. –

+2

Las validaciones se ejecutan en el orden en que están definidas, por lo que dependerá de eso. – edgerunner

+1

Esto funcionó para mí, pero ¿hay alguna otra manera de hacer lo mismo? – digitalWestie

8

De hecho, recomendaría tomar este código de un método de validación y ponerlo en una "valid_bank_account?" método que puede llamar manualmente cuando realmente desea presionar la API, especialmente porque es una operación costosa. Algunas razones para este comportamiento son que es posible que no desee ejecutar esta validación si el número de cuenta no ha cambiado o si solo está actualizando el registro.

 
def save_only_with_valid_bank_account 
    if @account.valid? && @account.valid_bank_number? && @account.save 
    ... 
    end 
end 

Es más tedioso pero garantiza que usted tenga control sobre cuándo se realiza la validación.

3

uso algo como esto

validates_presence_of :sort_code, :account_number 
validates_format_of :sort_code, :with => Regexes::SORT_CODE 
validates_format_of :account_number, :with => Regexes::ACCOUNT_NUMBER 
validate :check_valid_bank_account, :if => :should_i_call_custom_validation? 

def should_i_call_custom_validation? 
    # check for attributes or errors, errors.empty? should work 
end 

también un Proc debería funcionar también en este caso

validate :check_valid_bank_account, :if => Proc.new{|object| object.errors.empty?} 
Cuestiones relacionadas