variables locales opcionales en plantillas parciales de rails: ¿cómo salgo del (definido? foo) mess?


He sido un chico malo y he utilizado 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 parecía funcionar bien hasta hace poco, cuando (por ninguna razón pude discernir) las variables no pasadas comenzaron a comportarse como si hubieran sido definidas a cero (en lugar de indefinidas).

Como ha sido señalado por varias personas útiles en SO, http://api.rubyonrails.org/classes/ActionView/Base.html dice no usar

defined? foo

Y en su lugar usar

local_assigns.has_key? :foo

Estoy tratando de modificar mis métodos, pero eso significa cambiar muchas plantillas.

¿Puedo/debo simplemente cargar y hacer este cambio en todas las plantillas? ¿Hay algún problema debo tener cuidado? ¿Qué tan diligentemente necesito probar cada uno?

Author: brahn, 2010-01-14

12 answers

Hago esto:

<% some_local = default_value if local_assigns[:some_local].nil? %>
 289
Author: jonnii,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-17 22:03:33

Dado que local_assigns es un hash, también puedes usar fetch con el opcional default_value.

local_assigns.fetch :foo, default_value

Esto devolverá default_value si foo no se ha 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 es necesario.

 135
Author: Pablo Cantero,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-02-01 15:52:00

¿Qué tal

<% foo ||= default_value %>

Esto dice "use foo si no es nil o verdadero. De lo contrario asignar default_value a foo "

 77
Author: hgmnz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-13 22:35:17

Creo que esto debería repetirse aquí (de http://api.rubyonrails.org/classes/ActionView/Base.html):

Si necesita averiguar si a cierta variable local se le ha asignado un valor en una llamada de renderizado en particular, debe usar el siguiente patrón:

<% if local_assigns.has_key? :headline %>
  Headline: <%= headline %>
<% end %>

Testing using defined? el titular no funcionará. Esta es una restricción de implementación.

 10
Author: gamov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-06-09 06:31:18

Sé que es un hilo viejo pero aquí está mi pequeña contribución: usaría local_assigns[:foo].presence en un condicional dentro del parcial. Luego establezco foo solo cuando es necesario en la llamada de renderizado:

<%= render 'path/to/my_partial', always_present_local_var: "bar", foo: "baz" %>

Echa un vistazo a la guía oficial de Rails aquí . Válido desde RoR 3.1.0.

 3
Author: microspino,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-28 22:04:56

En mi caso, utilizo:

<% variable ||= "" %>

En mi parcial.
No tengo idea si eso es bueno, pero para mi está bien

 3
Author: Moises Portillo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-05-28 22:50:59

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] %>
 1
Author: Daniel OCallaghan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-13 03:39:44

Esto es un derivado de la respuesta de Pablo. Esto me permite establecer un valor predeterminado ('full'), y al final,' mode ' 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') %>
 1
Author: sethcall,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-13 15:59:03

Más intuitivo y compacto:

<% some_local = default_value unless local_assigns[:some_local] %>

 0
Author: muirbot,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-16 20:07:34

Si no desea pasar la variable local a partial cada vez que la llame, haga lo siguiente:

<% local_param = defined?(local_param) ? local_param : nil %>

De esta manera se evita el error undefined variable. Esto le permitirá llamar a su parcial con / sin variables locales.

 0
Author: Haris Krajina,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-04 19:32:14

Ruby 2.5

Erb

Es posible, pero debe declarar sus valores predeterminados en el ámbito.

VARIABLE la palabra para 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 %>
...
 0
Author: dimpiax,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-12 15:52:24

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 detalles sobre cómo y por qué.

Tenga en cuenta que esta solución le permite pasar nil o false como el valor sin que se anule.

 -5
Author: Jaime Cham,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-03-30 02:16:29