2011-08-18 16 views
6

Se ho un modello di ActiveRecord come segueRubino di valutazione di classe, validates_inclusion_of con i dati dinamici

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

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

Questo non funziona perché il metodo allowed_types non è stato definito al momento in cui viene valutata la convalida. Tutte le soluzioni a cui posso pensare fondamentalmente ruotano attorno allo spostamento della definizione del metodo sopra la convalida in modo che sia disponibile quando necessario.

Apprezzo che questa potrebbe essere più una questione di stile di codifica di qualsiasi altra cosa (voglio tutte le mie convalide nella parte superiore del modello e i metodi in basso) ma ritengo che ci dovrebbe essere una sorta di soluzione a questo, forse comportando una valutazione pigra del carico iniziale del modello?

è quello che voglio fare anche possibile? Dovrei solo definire il metodo sopra la convalida o c'è una soluzione di convalida migliore per ottenere ciò che voglio.

+0

@eightbitraptor ... provare ': in => Foo.allowed_types' invece di': in => self.allowed_types' ... beacause penso 'self' sarebbe riferimento all'oggetto di 'Foo' invece di' Foo' – rubyprince

risposta

10

Dovresti essere in grado di utilizzare la sintassi lambda per questo scopo. Forse in questo modo:

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 

In questo modo si valuterà il blocco lambda ad ogni convalida e passare l'istanza di Foo al blocco. Restituirà quindi il valore di allowed_types in quell'istanza in modo che possa essere validato in modo dinamico.

Si noti inoltre che ho rimosso self. dalla dichiarazione del metodo allowed_types perché ciò creerebbe un metodo di classe anziché un metodo di istanza che è ciò che si desidera qui.

+0

ottimi ringraziamenti, quello era esattamente il punto in cui stavo cercando di andare con quello, ma non mi ero reso conto che passare un oggetto nel lambda avrebbe passato l'oggetto che veniva convalidato. – eightbitraptor

+0

Vorrei poter votare due volte. – patrickmcgraw

+1

Puoi usare ': in => lambda (&: allowed_types)' per una sintassi ancora più compatta. – radiospiel

0

Il: in opzione del metodo validates_inclusion_of non sembra accettare un lambda o Proc. Ecco un altro approccio:

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 
Problemi correlati