2011-01-19 14 views
5

Ho molti modelli e relazioni. A causa di questo fatto, c'è sacco di chiamate in views/controllori, che assomigliano a questo:Qual è il modo corretto per verificare la presenza di oggetti in Rails/Ruby?

@object.something.with_something.value 

Alcuni parte della catena può finire per essere pari a zero, che è perfettamente ok. Qual è il modo corretto/pulito/veloce per verificare l'esistenza dell'oggetto terminale?

chiama qualcosa come:

@object.something.with_something.value if defined? @object.something.with_something.value 

considerato ok?

+0

Questa domanda non è veramente formulata in modo molto chiaro ... Ti interessa solo '@ object.something.with_something.value' essere' nil' o sei preoccupato per il 'NoMethodError' che si alza se qualcosa nel la catena è 'nil'? Presumo quest'ultimo? –

risposta

8

In modo nativo, è necessario utilizzare l'operatore && (non defined?), ma questo può diventare molto dettagliato, molto rapidamente.

Così, invece di fare questo:

(@object && @object.something && @object.something.with_something && 
    @object.something.with_something.value) 

È possibile fare questo quando ActiveSupport è presente:

@object.try(:something).try(:with_something).try(:value) 

o installare il invocation construction kit e utilizzare i suoi strumenti di valutazione custodito:

Ick::Maybe.belongs_to YourClass 
maybe(@object) { |obj| obj.something.with_something.value } 
2

what.you.are.doing è talvolta denominato "Train wreck". Viene anche descritto come una violazione della legge di Demetra.

Detto questo, penso che ci sia qualcosa chiamato "andand" che può aiutare con quello che stai facendo.

+1

Sì, 'Object # andand' è una soluzione, ma cerco di evitarlo - è piuttosto strano introdurre una dipendenza che essenzialmente ti dà un metodo.Inoltre, esegue il patch-scimmia per default della classe 'Object', che è terribile. –

3

È meglio organizzare il resto del codice per vedere questo problema al massimo l'ultimo oggetto in una catena.

defined? non farà quello che vuoi. Qualcosa può essere defined? e nil allo stesso tempo.

Quando il problema è limitato a l'ultimo attributo in una catena di riferimenti:

@object.something.with_something.value if @object.something.with_something 

potrei approfittare dei fatti che:

nil.to_a => [] 
nil.to_s => '' 
nil.to_f => 0.0 
nil.to_i => 0 

Quindi, se si sa che qualcosa sta nil o Array, spesso è possibile scrivere codice migliore senza alcun condizionale scrivendo qualcosa del tipo:

something.to_a.each do |e| 
    . . . 
+0

Sì, ho riletto l'OP e ho capito cosa intendevi. Ho letto un po 'la domanda dell'OP perché sapevo che la domanda a cui rispondevo era più probabile che fosse il problema in cui si era imbattuto. –

+2

Ad essere onesti, non sono un grande fan della tua soluzione. L'ho visto comparire un paio di volte e lo rimuovo ogni volta che lo vedo perché ritengo che il codice sia meno leggibile. Altri metodi come 'try' e' forse' risolvono il problema più in generale e lo fanno in un modo più leggibile. –

+0

So cosa intendi, ma quando ho scoperto che 'nil' aveva le funzioni specializzate di' Object' per to_ * x * ho pensato: * Matz è davvero un genio. * Ad esempio, ** (something.somethingelse || []). each do ** è davvero una specie di goffo al confronto. – DigitalRoss

0

Un'altra opzione è utilizzare Null Object pattern per garantire che nessuno di questi oggetti sia sempre nullo. Probabilmente, se il tuo codice sta per accedere a catena in questo modo, è necessario definire sempre .

+0

La parte migliore di questo è che in Ruby, questo schema può essere efficacemente implementato in modo trasparente. Questo è essenzialmente il modo in cui il kit di costruzione di invocazione implementa "forse" sotto il cofano. Fornisce un 'IdentityWrapper' e un' GuardWrapper'. 'GuardWrapper' ha essenzialmente lo stesso scopo di un oggetto nullo in quel modello, ad eccezione del fatto che il wrapper può essere rimosso automaticamente al termine della valutazione del blocco. –

Problemi correlati