Rails 3: el envoltorio "campo con errores" cambia el aspecto de la página. Cómo evitar esto?


Campo de correo electrónico:

<label for="job_client_email">Email: </label> 
<input type="email" name="job[client_email]" id="job_client_email">

Se ve así:

sin_error

Pero, si la validación de correo electrónico falla, se convierte en:

<div class="field_with_errors">
  <label for="job_client_email">Email: </label>
</div> 
<div class="field_with_errors">
  <input type="email" value="wrong email" name="job[client_email]" id="job_client_email">
</div>

Que se ve así:

with_error

¿Cómo podría evitar este cambio de apariencia ?

Author: Misha Moroshko, 2011-03-11

12 answers

Debe anular ActionView::Base.field_error_proc. Actualmente se define como esto dentro de ActionView::Base:

 @@field_error_proc = Proc.new{ |html_tag, instance| 
   "<div class=\"field_with_errors\">#{html_tag}</div>".html_safe
 }

Puedes anularlo poniendo esto en la clase de tu aplicación dentro de config/application.rb:

config.action_view.field_error_proc = Proc.new { |html_tag, instance| 
  html_tag
}

Reinicie el servidor rails para que este cambio surta efecto.

 225
Author: Ryan Bigg,
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-02-06 00:46:46

La diferencia visual que está viendo está sucediendo porque el elemento div es un elemento de bloque. Agregue este estilo a su archivo CSS para que se comporte como un elemento en línea:

.field_with_errors { display: inline; }
 98
Author: dontangg,
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-03-11 01:38:35

Actualmente uso esta solución, colocada en un inicializador:

ActionView::Base.field_error_proc = Proc.new do |html_tag, instance|
  class_attr_index = html_tag.index 'class="'

  if class_attr_index
    html_tag.insert class_attr_index+7, 'error '
  else
    html_tag.insert html_tag.index('>'), ' class="error"'
  end
end

Esto me permite simplemente agregar un nombre de clase a la etiqueta apropiada, sin crear elementos adicionales.

 69
Author: Phobetron,
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-12-05 02:29:20

El código extra está siendo añadido por ActionView::Base.field_error_proc. Si no estás usando field_with_errors para darle estilo a tu formulario, puedes anularlo en application.rb:

config.action_view.field_error_proc = Proc.new { |html_tag, instance| html_tag.html_safe }

Alternativamente, puedes cambiarlo a algo que se adapte a tu IU:

config.action_view.field_error_proc = Proc.new { |html_tag, instance| "<span class='field_with_errors'>#{html_tag}</span>".html_safe }
 20
Author: Dan Cheail,
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-03-11 01:46:24

Además de @phobetron answer, que no funciona cuando tienes otra etiqueta con atributo de clase, como <label for="..."><i class="icon my-icon"></i>My field</label>.

Hice algunos cambios en su solución:

# config/initializers/field_with_error.rb

ActionView::Base.field_error_proc = Proc.new do |html_tag, instance|
  class_attr_index = html_tag.index('class="')
  first_tag_end_index = html_tag.index('>')

  if class_attr_index.nil? || first_tag_end_index > class_attr_index
    html_tag.insert(class_attr_index + 7, 'error ')
  else
    html_tag.insert(first_tag_end_index, ' class="error"')
  end
end
 4
Author: Hugo Demiglio,
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
2016-03-28 20:02:11

Estoy trabajando con Rails 5 y Materialize-Sass y estoy teniendo algunos problemas con el comportamiento predeterminado de Rails para tratar las validaciones de campos fallidas como en la imagen de abajo y fue debido al extra div agregado a los campos de entrada donde la validación falló.

introduzca la descripción de la imagen aquí

Trabajando con la respuesta de @Phobetron y modificando también la respuesta de Hugo Demiglio. Hice algunos ajustes a esos bloques de código y tengo algo que funciona bien en lo siguiente casos:

  • Si tanto input como label tienen su propio atributo class en cualquier lugar
    • <input type="my-field" class="control">
    • <label class="active" for="...">My field</label>
  • Si las etiquetas input o label no tienen un atributo class
    • <input type="my-field">
    • <label for="...">My field</label>
  • si la etiqueta label tiene otra etiqueta dentro con la etiqueta class attribute
    • <label for="..."><i class="icon-name"></i>My field</label>

En todos esos casos, la clase error se agregará a las clases existentes en el atributo class si existen o se creará si no está presente en las etiquetas label o input.

ActionView::Base.field_error_proc = Proc.new do |html_tag, instance|
    class_attr_index = html_tag.index('class="')
    first_tag_end_index = html_tag.index('>')

    # Just to inspect variables in the console
    puts ' ' * 50
    pp(html_tag)
    pp(class_attr_index)
    pp(first_tag_end_index)

    if class_attr_index.nil? || class_attr_index > first_tag_end_index
        html_tag.insert(first_tag_end_index, ' class="error"')
    else
        html_tag.insert(class_attr_index + 7, 'error ')
    end

    # Just to see resulting tag in the console
    pp(html_tag)
end

Espero que pueda ser útil para alguien con las mismas condiciones como yo.

 4
Author: Alex Ventura,
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
2017-01-31 03:59:05

Si por alguna razón sigues trabajando en Rails 2 (como yo) echa un vistazo al post SO aquí.

Ofrece un script para poner en inicializadores.

 2
Author: ScottJShea,
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
2017-05-23 12:32:29

Una cosa a tener en cuenta (como descubrí trabajando con esto hoy) es que si flotan ya sea la etiqueta o los campos de entrada (estoy flotando todos los campos de entrada a la derecha), el css romperá incluso si se sobrescribe ActionView::Base.field_error_proc.

Una alternativa es bajar un nivel más profundo en el formato CSS de la siguiente manera:

.field_with_errors label {
  padding: 2px;
  background-color: red;
}

.field_with_errors input[type="text"] {
  padding: 3px 2px;
  border: 2px solid red;
}
 2
Author: Kevin Reeth,
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-06-06 19:53:23

Hice una opción para desactivar esta cosa terrible para algunos objetos

# config/initializers/field_error_proc.rb

module ActiveModel::Conversion
  attr_accessor :skip_field_error_wrapper
end

ActionView::Base.field_error_proc = Proc.new {|html_tag, instance|
  if instance.object && instance.object.skip_field_error_wrapper
    html_tag.html_safe
  else
    "<div class=\"field_with_errors\">#{html_tag}</div>".html_safe
  end
}

Así que puede usarlo de esta manera:

@user.skip_field_error_wrapper = true
form_for(@user) do |f|
  ...
end
 2
Author: Pavel Evstigneev,
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-01-15 06:29:33

Esta es mi solución basada en la respuesta de @Phobetron. Al colocar este código en application.rb, sus etiquetas <p> y <span> generadas por las llamadas form.error :p correspondientes recibirán la etiqueta css fields_with_errors. El resto recibirá la clase CSS error.

config.action_view.field_error_proc = Proc.new { |html_tag, instance|
  class_attr_index = html_tag.index 'class="'

  if class_attr_index
    # target only p's and span's with class error already there
    error_class = if html_tag =~ /^<(p|span).*error/
      'field_with_errors '
    else
      'error '
    end

    html_tag.insert class_attr_index + 7, error_class
  else
    html_tag.insert html_tag.index('>'), ' class="error"'
  end
}

Encontré de esta manera la más flexible y discreta de todas las anteriores para estilizar la respuesta a través de mis formularios.

 1
Author: dgilperez,
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
2013-11-11 13:51:18

Si es solo para propósitos de estilo (no te importa el div), puedes agregar esto a tu css:

div.field_with_errors {
 display: inline;
}

El div actuará como un span y no interferirá con su diseño (ya que div es un elemento de bloque – display: block;– por defecto, causará una nueva línea después de que se cierre; span es inline, por lo que no lo hace).

 1
Author: user2985898,
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-28 14:44:13

Si solo se trata de problemas de estilo, podemos sobrescribir "field_with_errors". Pero como eso podría afectar a otras formas en nuestra aplicación, es mejor sobrescribir la clase "field_with_errors" con solo en esa forma.

Considerando 'parent_class' es una de las clases padre para el campo de error del formulario (ya sea la clase del formulario o la clase de cualquiera de los elementos padre para el campo de error), entonces

  .parent_class .field_with_errors {
    display: inline;
  }

Solucionará el problema, así como, no perturbará ninguna otra forma en nuestra aplicación como bien.

O

Si necesitamos anular el estilo de "field_with_errors" para toda la aplicación, entonces como dijo @dontangg,

.field_with_errors { display: inline; } 

Hará la corrección. Espero que ayude :)

 0
Author: Prem,
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-04-21 12:00:30