2011-01-19 12 views
5

Tengo muchos modelos y relaciones. Debido a este hecho, hay muchas llamadas en views/controladores, que se parecen a esto:¿Cuál es la forma correcta de verificar la existencia de objetos en Rails/Ruby?

@object.something.with_something.value 

Una parte de la cadena puede llegar a ser nula, lo cual es perfectamente aceptable. ¿Cuál es la forma correcta/limpia/rápida de verificar la existencia del objeto terminal?

está llamando a algo como:

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

Considerado bien?

+0

Esta pregunta no está muy bien redactada ... ¿Le importa '@ object.something.with_something.value' siendo' nil' o le preocupa el 'NoMethodError' que se sube si hay algo en el la cadena es 'nil'? Supongo que lo último? –

Respuesta

8

Nativamente, necesitaría usar el operador && (no defined?), pero esto puede ser muy detallado, muy rápidamente.

Así que en lugar de hacer esto:

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

Puede hacer esto cuando ActiveSupport está presente:

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

o instalar el invocation construction kit y utilizar sus herramientas de evaluación vigilados:

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

what.you.are.doing a veces se denomina "accidente de tren". También se describe como una violación de la Ley de Demeter.

Habiendo dicho eso, creo que hay algo llamado "andand" que puede ayudar con lo que estás haciendo.

+1

Sí, 'Object # andand' es una solución, pero trato de evitarlo, es un poco extraño introducir una dependencia que esencialmente te da un método.Además, mono-parches de la clase 'Object' por defecto, que es horrible. –

3

Es mejor organizar el resto de su código para ver este problema como máximo el último objeto en una cadena.

defined? no hará lo que quiera. Algo puede ser defined? y nil al mismo tiempo.

Cuando el problema se limita al último atributo en una cadena de referencias:

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

que podrían beneficiarse de los siguientes hechos:

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

Por lo tanto, si usted sabe que algo anda ya sea nil o Array, a menudo puede escribir mejor el código sin ningún condicionales en absoluto escribiendo algo como:

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

Sí, releí el OP y descubrí lo que quería decir. Leí un poco sobre la pregunta del OP porque sabía que la pregunta que respondí era más probable que fuera el problema con el que realmente se topó. –

+2

Para ser sincero, no soy un gran admirador de su solución. Lo he visto aparecer varias veces y lo elimino cada vez que lo veo porque creo firmemente que hace que el código sea menos legible. Otros métodos como 'try' y' maybe' resuelven el problema de manera más general y lo hacen de una manera más legible. –

+0

Sé a qué te refieres, pero cuando descubrí que 'nil' tenía funciones especializadas' Object''s to_ * x *, pensé: * Matz es realmente un genio. * Por ejemplo, ** (something.somethingelse || []). Cada do ** es realmente torpe en comparación. – DigitalRoss

0

Otra opción es utilizar el Null Object pattern para garantizar que ninguno de esos objetos sea nulo. Podría decirse que si su código va a acceder a la cadena de esa manera, entonces siempre debe definirse algo.

+0

La mejor parte de esto es que en Ruby, este patrón se puede implementar de manera transparente. Eso es esencialmente cómo el kit de construcción de invocación implementa 'tal vez' debajo del capó. Proporciona un 'IdentityWrapper' y un' GuardWrapper'. El 'GuardWrapper' tiene esencialmente el mismo propósito que un objeto nulo en ese patrón, excepto que el contenedor se puede quitar automáticamente cuando se completa la evaluación del bloque. –

Cuestiones relacionadas