web-dev-qa-db-fra.com

Rails 3: le wrapper "champ avec erreurs" modifie l'apparence de la page. Comment éviter cela?

Courriel:

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

ressemble à ça:

without_error

Mais si la validation de l'e-mail échoue, cela devient:

<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>

qui ressemble à ceci:

with_error

Comment pourrais-je éviter ce changement d'aspect?

129
Misha Moroshko

Vous devriez remplacer ActionView::Base.field_error_proc. Il est actuellement défini comme ceci dans ActionView::Base:

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

Vous pouvez le remplacer en le mettant dans la classe de votre application à l'intérieur de config/application.rb:

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

Redémarrez le serveur Rails pour que cette modification soit prise en compte).

229
Ryan Bigg

La différence visuelle que vous voyez se produit parce que l'élément div est un élément de bloc. Ajoutez ce style à votre fichier CSS pour le faire se comporter comme un élément en ligne:

.field_with_errors { display: inline; }
99
dontangg

J'utilise actuellement cette solution, placée dans un initialiseur:

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

Cela me permet simplement d'ajouter un nom de classe à la balise appropriée, sans créer d'éléments supplémentaires.

70
Phobetron

Le code supplémentaire est ajouté par ActionView::Base.field_error_proc. Si vous n'utilisez pas field_with_errors pour styler votre formulaire, vous pouvez le remplacer dans application.rb:

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

Alternativement, vous pouvez le changer pour quelque chose qui convient à votre interface utilisateur:

config.action_view.field_error_proc = Proc.new { |html_tag, instance| "<span class='field_with_errors'>#{html_tag}</span>".html_safe }
20
Dan Cheail

Je travaille avec Rails 5 et Materialise-Sass et j'ai quelques problèmes avec le comportement par défaut de Rails pour traiter échoué les validations de champs comme dans l’image ci-dessous et c’est à cause du supplément de div ajouté aux champs de saisie où la validation a échoué.

enter image description here

Travailler avec @Phobetron répond et modifie également la réponse de Hugo Demiglio. J'ai apporté quelques ajustements à ces blocs de code et quelque chose fonctionne bien dans les cas suivants:

  • Si input et label ont chacun leur propre attribut class n'importe où
    • <input type="my-field" class="control">
    • <label class="active" for="...">My field</label>
  • Si les balises input ou label n'ont pas d'attribut class
    • <input type="my-field">
    • <label for="...">My field</label>
  • si la balise label a une autre balise à l'intérieur avec le class attribute
    • <label for="..."><i class="icon-name"></i>My field</label>

Dans tous ces cas, la classe error sera ajoutée aux classes existantes dans l'attribut class s'il existe ou elle sera créée si elle n'est pas présente dans le label ou saisissez des balises .

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

J'espère que cela pourrait être utile pour quelqu'un qui a les mêmes conditions que moi.

4
Alex Ventura

En plus de @phobetron answer, ce qui ne fonctionne pas si vous avez une autre balise avec un attribut class, comme <label for="..."><i class="icon my-icon"></i>My field</label>.

J'ai fait quelques changements sur sa solution:

# 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
Hugo Demiglio

J'ai fait une option pour désactiver cette chose terrible pour certains objets

# 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
}

Alors peut l'utiliser comme ça:

@user.skip_field_error_wrapper = true
form_for(@user) do |f|
  ...
end
2
Pavel Evstigneev

Si pour une raison quelconque vous travaillez toujours sur Rails 2 (comme je le suis), consultez le SO post ici .

Il propose un script à mettre dans les initialiseurs.

2
ScottJShea

Une chose à garder à l’esprit (comme je l’ai découvert aujourd’hui) est que, si vous flottez l’étiquette ou les champs d’entrée (je flotte tous les champs d’entrée à droite), le css se cassera même si vous écrasez ActionView :: Base.field_error_proc.

Une alternative consiste à abandonner un niveau plus profond dans la mise en forme CSS comme ceci:

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

.field_with_errors input[type="text"] {
  padding: 3px 2px;
  border: 2px solid red;
}
2
Kevin Reeth

Si c'est uniquement à des fins de style (vous ne vous occupez pas de div), vous pouvez simplement ajouter ceci à votre css:

div.field_with_errors {
 display: inline;
}

Le div agira comme un span et n'interférera pas avec votre conception (puisque div est un élément de bloc - display: block; _ Par défaut, une nouvelle ligne sera créée après sa fermeture. span est inline, donc ce n'est pas le cas).

1
user2985898

C’est ma solution qui s’appuie sur la réponse de @ Phobetron. Placer ce code dans application.rb, votre <p> et <span> tags générés par le form.error :p les appels recevront le fields_with_errors balise css. Le reste recevra la classe CSS error CSS.

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
}

Je trouvais ainsi le moyen le plus flexible et le plus discret de tous les précédents de styliser la réponse dans mes formulaires.

1
dgilperez

S'il ne s'agit que de problèmes de style, nous pouvons écraser "field_with_errors". Mais comme cela pourrait affecter d'autres formulaires dans notre application, il est préférable d'écraser la classe "field_with_errors" dans ce formulaire uniquement.

Considérant que 'parent_class' est l'une des classes parentes du champ d'erreur du formulaire (la classe du formulaire ou la classe de l'un des éléments parents du champ d'erreur), puis

  .parent_class .field_with_errors {
    display: inline;
  }

Cela résoudra le problème aussi bien que, cela ne perturbera pas d'autres formes dans notre application.

OR

Si nous devons remplacer le style de "field_with_errors" pour toute une application, alors comme @dontangg l'a dit,

.field_with_errors { display: inline; } 

fera le correctif. J'espère que ça aide :)

0
Prem

Si vous souhaitez simplement désactiver les erreurs pour certains éléments, par exemple cases à cocher, vous pouvez le faire:

ActionView::Base.field_error_proc = Proc.new do |html_tag, instance|
  doc = Nokogiri::HTML::Document.parse(html_tag)
  if doc.xpath("//*[@type='checkbox']").any?
    html_tag
  else
    "<div class=\"field_with_errors\">#{html_tag}</div>".html_safe
  end
end
0
Tintin81