ruby on rails - rails - Variables locales opcionales en plantillas parciales de rieles: ¿cómo puedo salir del lío(definido? foo)?
render partial mvc (12)
He sido un niño malo y utilicé la siguiente sintaxis en mis plantillas parciales para establecer valores predeterminados para las variables locales si un valor no se definió explícitamente en el hash: locals al representar el parcial:
<% foo = default_value unless (defined? foo) %>
Esto pareció funcionar bien hasta hace poco, cuando (sin ninguna razón pude discernir) las variables no pasadas comenzaron a comportarse como si hubieran sido definidas como nulas (en lugar de indefinidas).
Como han señalado varias personas útiles en SO, http://api.rubyonrails.org/classes/ActionView/Base.html dice no usar
defined? foo
y en lugar de usar
local_assigns.has_key? :foo
Estoy intentando modificar mis formas, pero eso significa cambiar muchas plantillas.
¿Puedo / debo cobrar por adelantado y hacer este cambio en todas las plantillas? ¿Hay algún truco que deba vigilar? ¿Qué tan diligentemente necesito probar cada uno?
Ruby 2.5
Erb
Es posible, pero debe declarar sus valores predeterminados en el ámbito.
VARIABLE la palabra para el reemplazo.
# index.html.erb
...
<%= render ''some_content'', VARIABLE: false %>
...
# _some_content.html.erb
...
<% VARIABLE = true if local_assigns[:VARIABLE].nil? %>
<% if VARIABLE %>
<h1>Do you see me?</h1>
<% end %>
...
Creo que esto debería repetirse aquí (de http://api.rubyonrails.org/classes/ActionView/Base.html ):
Si necesita averiguar si a una determinada variable local se le ha asignado un valor en una llamada de render en particular, necesita usar el siguiente patrón:
<% if local_assigns.has_key? :headline %>
Headline: <%= headline %>
<% end %>
Prueba utilizando definido? El titular no funcionará. Esta es una restricción de implementación.
Creo que una mejor opción que permite múltiples variables predeterminadas:
<% options = local_assigns.reverse_merge(:include_css => true, :include_js => true) %>
<%= include_stylesheets :national_header_css if options[:include_css] %>
<%= include_javascripts :national_header_js if options[:include_js] %>
Dado que local_assigns
es un hash, también puede usar fetch con el default_value
opcional.
local_assigns.fetch :foo, default_value
Esto devolverá default_value
si foo
no fue establecido.
ADVERTENCIA:
Tenga cuidado con local_assigns.fetch :foo, default_value
cuando default_value
es un método, ya que se llamará de todos modos para pasar su resultado a fetch
.
Si su default_value
es un método, puede envolverlo en un bloque: local_assigns.fetch(:foo) { default_value }
para evitar su llamada cuando no sea necesario.
En mi caso, yo uso:
<% variable ||= "" %>
en mi parcial
No tengo idea si eso es bueno pero para mi está bien.
Esta es una derivada de la respuesta de Pablo. Esto me permite establecer un valor predeterminado (''completo''), y al final, ''modo'' se establece tanto en local_assigns como en una variable local real.
haml / slim:
- mode ||= local_assigns[:mode] = local_assigns.fetch(:mode, ''full'')
erb
<% mode ||= local_assigns[:mode] = local_assigns.fetch(:mode, ''full'') %>
Hago esto:
<% some_local = default_value if local_assigns[:some_local].nil? %>
Más intuitivo y compacto:
<% some_local = default_value unless local_assigns[:some_local] %>
Qué tal si
<% foo ||= default_value %>
Esto dice "use foo
si no es nulo o verdadero. De lo contrario, asigne el valor default_value
a foo"
Sé que es un hilo viejo, pero aquí está mi pequeña contribución: usaría local_assigns[:foo].presence
en un conditional dentro del parcial. Luego configuro foo
solo cuando sea necesario en la llamada de render:
<%= render ''path/to/my_partial'', always_present_local_var: "bar", foo: "baz" %>
Echa un vistazo a la guía oficial de rieles aquí . Válido desde RoR 3.1.0.
Se puede crear un ayudante para que se vea así:
somearg = opt(:somearg) { :defaultvalue }
Implementado como:
module OptHelper
def opt(name, &block)
was_assigned, value = eval(
"[ local_assigns.has_key?(:#{name}), local_assigns[:#{name}] ]",
block.binding)
if was_assigned
value
else
yield
end
end
end
Ver mi blog para más detalles sobre cómo y por qué.
Tenga en cuenta que esta solución le permite pasar nulo o falso como valor sin que se invalide.
Si no quiere pasar una variable local a parcial cada vez que la llame, haga esto:
<% local_param = defined?(local_param) ? local_param : nil %>
De esta manera evitas errores de undefined variable
. Esto le permitirá llamar a su parcial con / sin variables locales.