web-dev-qa-db-fra.com

f.error_messages dans Rails 3.0

Rails 3.0 déconseillé f.error_messages et nécessite maintenant un plugin pour fonctionner correctement - je veux cependant apprendre à afficher les messages d'erreur de la (nouvelle) manière native. Je suis le guide de démarrage , qui utilise la méthode obsolète lors de la mise en œuvre du formulaire de commentaires. Par exemple:

<h2>Add a comment:</h2>
<%= form_for([@post, @post.comments.build]) do |f| %>
  <%= f.error_messages %>
<div class="field">
  <% f.label :commenter  %><br />
  <%= f.text_field :commenter  %>
</div>
<div class="field">
  <%= f.label :body %><br />
  <%= f.text_area :body %>
</div>
<div class="actions">
  <%= f.submit %>
</div>
<% end %>

Voici la bonne façon de le faire (telle que générée par l'échafaudage):

<%= form_for(@post) do |f| %>
  <% if @post.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@post.errors.count, "error") %> prohibited this post from being saved:</h2>

      <ul>
      <% @post.errors.full_messages.each do |msg| %>
        <li><%= msg %></li>
      <% end %>
      </ul>
    </div>
  <% end %>
 . . . 

Je comprends que j'utilise le @post variable dans le dernier exemple, mais à quelle variable dois-je faire référence dans le premier pour obtenir les messages d'erreur pour la création de commentaires?

42
Craig Smitham

Je viens de me pencher sur les problèmes de github docrails, et ils ont décidé de supprimer f.error_messages au lieu d'expliquer comment faire la validation des commentaires.

0
bunwich

La meilleure façon et propre d'implémenter error_messages dans votre formulaire est d'implémenter error_messages dans un FormBuilder.

Par exemple, voici la méthode error_messages que j'ai implémentée pour mon dernier projet. En implémentant votre propre FormBuilder, vous pouvez suivre les règles et les styles de votre webdesigner ... Voici un exemple qui affichera la liste des erreurs dans ul/li avec quelques styles personnalisés:

class StandardBuilder < ActionView::Helpers::FormBuilder
  def error_messages
    return unless object.respond_to?(:errors) && object.errors.any?

    errors_list = ""
    errors_list << @template.content_tag(:span, "There are errors!", :class => "title-error")
    errors_list << object.errors.full_messages.map { |message| @template.content_tag(:li, message) }.join("\n")

    @template.content_tag(:ul, errors_list.html_safe, :class => "error-recap round-border")
  end
end

Puis sous mes formes:

= f.error_messages

Et c'est tout.

23
Nicolas Blanco

Je suis sûr que tout ce que vous avez à faire est de faire référence à @post.comments

Vous pouvez donc faire quelque chose comme:

<% @post.comments.each do |comment| %>
    <% if comment.errors.any? %>

    <% comment.errors.full_messages.each do |msg| %>
        <li><%= msg %></li>
    <% end %>

    <% end %>
<% end %>

Ou extrayez simplement toutes les erreurs:

comment_errors = @post.comments.map(&:errors)

puis parcourez-les dans votre logique d'affichage pour générer chacune des erreurs de commentaire.

13
Lukas

Cette fonctionnalité existe en tant que gemme autonome dynamic_form .

Ajoutez ce qui suit à votre Gemfile

gem 'dynamic_form'

Depuis la page github :

DynamicForm contient quelques méthodes pour vous aider à gérer vos modèles Rails3, ce sont:

  • input(record, method, options = {})
  • form(record, options = {})
  • error_message_on(object, method, options={})
  • error_messages_for(record, options={})

Il ajoute également f.error_messages Et f.error_message_on À vos générateurs de formulaires.

7
Justin Tanner

Voici ma solution à toute la scène d'erreur.

J'ai créé un partiel qui utilise simplement une variable de modèle que l'on passerait lors du rendu:

<%# app/views/errors/_error.html.erb %>

<%= content_for :message do %>
  <% if model.errors.any? %>
    <ul>
      <% model.errors.full_messages.each do |msg| %>
        <li><%= msg %></li>
      <% end %>
    </ul>
  <% end %>
<% end %>

Vous pouvez facilement ajouter des noms de classe et/ou id dynamiques HTML basés sur le nom du modèle, ainsi que des noms génériques.

J'ai des choses configurées où mes messages d'erreur s'affichent au même endroit dans un fichier de mise en page:

<%# app/views/layouts/application.html.erb %>

<%= yield :message %>

Si l'on ne voulait pas de cette fonctionnalité, supprimer le content_for dans le partiel ferait l'affaire.
Ensuite, dans la vue que vous voulez, vous pouvez simplement écrire:

<%= render 'errors/error', model: @some_model %>

On pourrait étendre cela en créant un partiel qui prend une collection et exploite l'erreur partielle ci-dessus:

<%# app/views/errors/_collection.html.erb %>

<% collection.each do |model| %>
  <%= render 'errors/error', model: model %>
<% end %>

Rendez-le avec:

<%= render 'errors/collection', collection: @some_model.some_has_many_association %>

J'aime cette façon. Il est simple, facile à gérer/à entretenir et incroyablement modifiable.
J'espère que ça aide!

EDIT: tout en HAML

-# app/views/errors/_error.html.haml

= content_for :message do
  - if model.errors.any?
    %ul
      - model.errors.full_messages.each do |msg|
        %li= msg


-# app/views/layouts/application.html.haml

= yield :message


= render 'errors/error', model: @some_model


-# app/views/errors/_collection.html.haml

- collection.each do |model|
  = render 'errors/errors', model: @some_model


= render 'errors/_collection', collection: @some_model.some_has_many_association
3
Benjamin

Je suppose que le tableau [@post, @post.comments.build] Est juste passé à polymorphic_path Dans form_for. Cela génère un chemin de sous-ressource pour les commentaires (comme /posts/1/comments Dans ce cas). Il semble donc que votre premier exemple utilise des commentaires comme sous-ressources pour les publications, non?.

Donc, en fait, le contrôleur qui sera appelé ici est le CommentsController. La raison pour laquelle la solution de Lukas ne fonctionne pas pour vous est peut-être que vous n'utilisez pas @ post.comments.build dans le contrôleur lors de la création du commentaire (peu importe que vous l'utilisiez dans la vue lors de l'appel de form_for). La méthode CommentsController#create Devrait ressembler à ceci (plus ou moins):

def create
  @post = Post.find(params[:post_id]
  @comment = @post.comments.build(params[:comment])

  if(@comment.save)
    # you would probably redirect to @post
  else
    # you would probably render post#show or wherever you have the form
  end
end

Ensuite, vous pouvez utiliser le code généré par l'échafaudage, remplacer uniquement la variable d'instance @post Par @comment Dans toutes les lignes sauf l'appel form_for.

Je pense que cela peut aussi être une bonne idée d'ajouter le @comment = @post.comment.build À la méthode du contrôleur qui affiche ce formulaire et d'utiliser form_for([@post, @comment], ...) pour conserver le contenu du formulaire affiché dans le formulaire en cas d'erreurs.

Si cela ne fonctionne pas et que vous ne pouvez pas le comprendre, veuillez ajouter votre méthode CommentsController#create À la question.

1
Matt