2008-10-26 11 views
26

Tengo un sistema de plantillas bastante antiguo escrito encima de ERB. Se basa en plantillas ERB almacenadas en la base de datos. Esos son leídos y renderizados. Cuando quiero pasar datos de una plantilla a otra utilizo el parámetro: locals al método de renderización de rieles. Para establecer las variables predeterminadas de esas variables en algunas plantillas, ¿utilizo el definido? método que simplemente me dice que si la variable local se ha definido y si no me inicializarlo con el valor por defecto de esta manera:definido? método en Ruby and Rails

unless defined?(perex) 
    perex = true 
end 

Estoy actualizando la aplicación a los últimos rieles y veo un comportamiento extraño. Básicamente, esto a veces funciona (a veces, Perex no está definido) y, a veces, no (Perex se define y establece en cero). Esto sucede sin cambiar nada más.

Tengo dos preguntas: ¿Hay alguna otra manera mejor que usar el definido? que no es confiable (fue confiable durante varios años en Rails 1.6 superior)? Tal forma no debería resultar en que vuelva a escribir todas las plantillas. He estado revisando los documentos de Ruby y no he podido encontrar nada sobre los definidos. método. ¿Fue obsoleto o simplemente estoy ciego?

Editar: El problema real fue causado por lo que parece ser un error de Ruby/eRB. A veces, el a menos que la declaración funcione, pero a veces no. Lo raro es que, incluso si se ejecutó la segunda línea , perex, stil permaneció nula para el resto del mundo. ¿Eliminar definido? resuelto eso.

Respuesta

36

Primero: en realidad, defined? is an operator.

Segundo: si entiendo bien su pregunta, la manera de hacerlo es con este lenguaje Ruby:

perex ||= true 

Eso va a asignar a cierto perex si es indefinido o nil. No es exactamente lo que hace su ejemplo, ya que el suyo no evalúa la asignación cuando el valor es nil, pero si se basa en eso, en mi opinión, sin verlo, no está escribiendo un código claro.

Edición: Como se ha señalado Honza, la afirmación anterior reemplazará el valor de perex cuando es false. Entonces propongo lo siguiente para volver a escribir el número mínimo de líneas:

perex ||= perex.nil? # Assign true only when perex is undefined or nil 
+10

Esto no es cierto. perex || = true hace lo mismo que perex = perex || true que establece el valor de "perex" en "true" si está indefinido, nulo o falso. El último caso rompería todo. – Honza

24

La forma más segura de las pruebas si un local está definido en una plantilla Rails es:

local_assigns[:perex] 

Esto está documentado en la API de Rails junto con la explicación de que defined? no se puede usar debido a una restricción de implementación.

+1

¿Qué sucede si el valor de perex es falso? –

+0

puede verificarlo usted mismo :) perex = true si local_assigns [: perex] .nil? – Hannes

12

Según la respuesta de mislav, busqué esa documentación en la API de Rails y la encontré en Class ActionView::Base (bajo el encabezado "Pasar variables locales a submodelos"). Sin embargo, valió la pena la búsqueda, ya que apenas decía nada más que mislav. Excepto que recomienda este patrón:

if local_assigns.has_key? :perex 
+0

¿Esto ahora está en desuso en favor de la tecla Hash #? pero creo que por ahora todavía funciona. –

6

Teniendo en considerationg mislav's original answer y KenB's elaboration, creo que el siguiente es el mejor enfoque absoluta (aunque estoy abierta a la opinión).Utiliza el método Hash#fetch de Ruby para recurrir a un valor alternativo si la clave no existe en el hash original.

perex = local_assigns.fetch(:perex, true) 

Esto es incluso mejor que el método ||= que la mayoría de los usuarios sugieren ya que a veces tendrá que permitir que false valores. Por ejemplo, el siguiente código Nunca permita que un valor false a ser aprobada en:

perex = local_assigns[:perex] || true 
Cuestiones relacionadas