2011-01-28 9 views
25

Sto costruendo una validazione personalizzata che controlla un Bank Account Number e sorta di codice con un'API esterna per verificare se esistono (ad esempio è una valida conto bancario nel Regno Unito corretta) . Poiché si tratta di un'operazione costosa, non voglio perdere tempo a colpire l'API a meno che il numero di conto e il codice di ordinamento non superino le convalide integrate di Rails.eseguire una convalida solo se tutte le altre convalide passano

Per esempio, ho queste convalide di base:

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 

Poi ho il mio convalida personalizzata:

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 

Quello che voglio per garantire è che la convalida personalizzata viene eseguita solo se il resto del modello è valido. Nessun punto pagando 25p per essere detto che non è stato fornito alcun numero di conto quando posso farlo da solo!

Sono consapevole che potrei scrivere una logica che controlla che i due attributi non siano vuoti e li abbini manualmente alla regex ... ma questo non sembra un modo molto Rails.

risposta

26

È possibile controllare la matrice errors e restituire.

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

io non credo che questo funzionerà se la convalida check_valid_bank_account viene eseguito prima delle altre convalide. –

+2

Le convalide vengono eseguite nell'ordine in cui sono definite, quindi dipende da questo. – edgerunner

+1

Questo ha funzionato per me ma esiste un altro modo per fare la stessa cosa? – digitalWestie

8

In realtà mi piacerebbe prendere questo codice da un metodo di convalida e inserirlo in un "valid_bank_account" separato? metodo che è possibile chiamare manualmente quando si desidera effettivamente raggiungere l'API, soprattutto perché è un'operazione costosa. Alcuni motivi di questo comportamento sono che potresti non voler eseguire questa convalida se il numero dell'account non è cambiato o se stai aggiornando il record.

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

È più noioso ma garantisce il controllo su quando si verifica effettivamente la convalida.

3

uso qualcosa di simile

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 

anche una Proc dovrebbe funzionare anche qui

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