ruby-on-rails - validations - rails validate scope
Rails 3: el contenedor "campo con errores" cambia el aspecto de la página. ¿Cómo evitar esto? (12)
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 como esto:
Pero, si la validación del 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í:
¿Cómo podría evitar este cambio de apariencia?
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.
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
Debería anular ActionView::Base.field_error_proc
. Actualmente se define como esto en ActionView::Base
:
@@field_error_proc = Proc.new{ |html_tag, instance|
"<div class=/"field_with_errors/">#{html_tag}</div>".html_safe
}
Puede anularlo poniendo esto en la clase de su aplicación dentro de config/application.rb
:
config.action_view.field_error_proc = Proc.new { |html_tag, instance|
html_tag
}
Reinicie el servidor de rieles para que este cambio surta efecto.
El código adicional está siendo agregado por ActionView::Base.field_error_proc
. Si no está utilizando field_with_errors
para field_with_errors
estilo a su formulario, puede anularlo en application.rb
:
config.action_view.field_error_proc = Proc.new { |html_tag, instance| html_tag.html_safe }
Alternativamente, puede cambiarlo a algo que se adapte a su UI:
config.action_view.field_error_proc = Proc.new { |html_tag, instance| "<span class=''field_with_errors''>#{html_tag}</span>".html_safe }
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 fields_with_errors
css. El resto recibirá la clase CSS de 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
}
De esta forma encontré el más flexible y discreto de todos los anteriores a la respuesta del estilo en mis formularios.
Estoy trabajando con Rails 5 y Materialize-Sass y estoy recibiendo algunos problemas con el comportamiento predeterminado de Rails para tratar validaciones de campo fallidas como en la imagen de abajo y fue debido a la div
adicional agregada a los campos de entrada donde falló la validación.
Trabajar con @Phobetron responde y modifica la respuesta de Hugo Demiglio también. Hice algunos ajustes a esos bloques de código y obtengo algo que funciona bien en los siguientes casos:
- Si tanto la
input
como lalabel
tienen su propio atributo declass
cualquier lugar-
<input type="my-field" class="control">
-
<label class="active" for="...">My field</label>
-
- Si las
label
input
o etiquetas no tienen un atributo declass
-
<input type="my-field">
-
<label for="...">My field</label>
-
- si la etiqueta tiene otra etiqueta adentro con el
class attribute
-
<label for="..."><i class="icon-name"></i>My field</label>
-
En todos esos casos, la clase de error
se agregará a las clases existentes en el atributo de class
si existe o se creará si no está presente en la etiqueta o etiquetas de entrada .
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 que yo.
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
}
Entonces puede usarlo así:
@user.skip_field_error_wrapper = true
form_for(@user) do |f|
...
end
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; }
Si es solo por motivos de estilo (no le importa el div
), puede agregar esto a su 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;
- de forma predeterminada, causará una nueva línea después de que se cierre; span
está en inline
, por lo que no )
Si por alguna razón todavía trabajas en Rails 2 (como yo), echa un vistazo a la publicación SO here .
Ofrece una secuencia de comandos para poner en inicializadores.
Si solo se trata de problemas de diseño, podemos sobreescribir "field_with_errors". Pero como eso podría afectar a otros formularios en nuestra aplicación, es mejor sobrescribir la clase "field_with_errors" con ese formulario solamente.
Teniendo en cuenta ''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 del elemento padre para el campo de error), luego
.parent_class .field_with_errors {
display: inline;
}
Solucionará el problema y no alterará ninguna otra forma en nuestra aplicación.
O
Si necesitamos anular el estilo de "campo_con_errores" para toda la aplicación, entonces como dijo @dontangg,
.field_with_errors { display: inline; }
hará la corrección. Espero eso ayude :)
Una cosa que hay que tener en cuenta (como descubrí trabajando en esto hoy) es que si flotas la etiqueta o los campos de entrada (estoy flotando todos los campos de entrada a la derecha), el css se romperá incluso si anulas ActionView :: Base.field_error_proc.
Una alternativa es bajar un nivel más profundo en el formato CSS de esta manera:
.field_with_errors label {
padding: 2px;
background-color: red;
}
.field_with_errors input[type="text"] {
padding: 3px 2px;
border: 2px solid red;
}