web-dev-qa-db-fra.com

Message d'erreur de validation entièrement personnalisé avec Rails

Utilisation de Rails J'essaie d'obtenir un message d'erreur du type "Le champ de la chanson ne peut pas être vide" lors de la sauvegarde. Faire ce qui suit:

validates_presence_of :song_rep_xyz, :message => "can't be empty"

... affiche uniquement "Song Rep XYW ne peut pas être vide", ce qui n'est pas satisfaisant car le titre du champ n'est pas convivial. Comment puis-je changer le titre du champ lui-même? Je pourrais changer le nom réel du champ dans la base de données, mais j'ai plusieurs champs "chanson" et j'ai besoin d'avoir des noms de champs spécifiques.

Je ne veux pas pirater le processus de validation de Rails et j'estime qu'il devrait y avoir un moyen de résoudre ce problème.

244
marcgg

Maintenant, le moyen accepté de définir les noms humanisés et les messages d'erreur personnalisés consiste à utiliser les paramètres régionaux .

# config/locales/en.yml
en:
  activerecord:
    attributes:
      user:
        email: "E-mail address"
    errors:
      models:
        user:
          attributes:
            email:
              blank: "is required"

Maintenant le nom humanisé et le message de validation de présence pour l'attribut "email" ont été modifiés.

Les messages de validation peuvent être définis pour un modèle spécifique + attribut, modèle, attribut ou globalement.

395
graywh

Dans votre modèle:

validates_presence_of :address1, :message => "Put some address please" 

À votre avis

<% m.errors.each do |attr,msg|  %>
 <%=msg%>
<% end %>

Si vous faites plutôt

<%=attr %> <%=msg %>

vous obtenez ce message d'erreur avec le nom de l'attribut 

address1 Put some address please

si vous voulez obtenir le message d'erreur pour un seul attribut 

<%= @model.errors[:address1] %>
62
Federico

Essaye ça. 

class User < ActiveRecord::Base
  validate do |user|
    user.errors.add_to_base("Country can't be blank") if user.country_iso.blank?
  end
end

J'ai trouvé ceci ici .

Voici une autre façon de le faire ..___ Ce que vous faites est de définir une méthode human_attribute_name sur la classe de modèle. Le nom de la colonne est transmis à la méthode sous forme de chaîne et renvoie la chaîne à utiliser dans les messages de validation.

class User < ActiveRecord::Base

  HUMANIZED_ATTRIBUTES = {
    :email => "E-mail address"
  }

  def self.human_attribute_name(attr)
    HUMANIZED_ATTRIBUTES[attr.to_sym] || super
  end

end

Le code ci-dessus est de ici

58
Maulin

Oui, il existe un moyen de faire cela sans le plugin! Mais ce n'est pas aussi propre et élégant que d'utiliser le plugin mentionné. C'est ici.

En supposant que ce soit Rails 3 (je ne sais pas si c'est différent dans les versions précédentes),

gardez ceci dans votre modèle:

validates_presence_of :song_rep_xyz, :message => "can't be empty"

et dans la vue, au lieu de quitter

@instance.errors.full_messages

comme ce serait le cas lorsque nous utilisons le générateur d'échafaudage, mettez:

@instance.errors.first[1]

Et vous n'obtiendrez que le message que vous avez spécifié dans le modèle, sans le nom de l'attribut.

Explication:

#returns an hash of messages, one element foreach field error, in this particular case would be just one element in the hash:
@instance.errors  # => {:song_rep_xyz=>"can't be empty"}

#this returns the first element of the hash as an array like [:key,"value"]
@instance.errors.first # => [:song_rep_xyz, "can't be empty"]

#by doing the following, you are telling Ruby to take just the second element of that array, which is the message.
@instance.errors.first[1]

Jusqu'à présent, nous affichons un seul message, toujours pour la première erreur. Si vous voulez afficher toutes les erreurs, vous pouvez effectuer une boucle dans le hachage et afficher les valeurs.

J'espère que ça a aidé.

16
Marco Antonio

Dans la méthode de validation personnalisée, utilisez:

errors.add(:base, "Custom error message")

comme add_to_base est obsolète.

errors.add_to_base("Custom error message")

14
amit_saxena

Rails3 Code avec des messages entièrement localisés:

Dans le modèle user.rb définir la validation

validates :email, :presence => true

Dans config/locales/en.yml

en:  
  activerecord:
    models: 
      user: "Customer"
    attributes:
      user:
        email: "Email address"
    errors:
      models:
        user:
          attributes:
            email:
              blank: "cannot be empty"
14
Lukas

Je recommande d'installer le custom_error_message gem (ou en tant que plugin ) écrit à l'origine par David Easley

Cela vous permet de faire des choses comme:

validates_presence_of :non_friendly_field_name, :message => "^Friendly field name is blank"
11
Ryan Bigg

En rapport avec les réponses acceptées _ et une autre réponse en bas de la liste

Je confirme que la branche de nanamkim de custom-err-msg fonctionne avec Rails 5 et avec les paramètres régionaux.

Il vous suffit de commencer le message de paramètres régionaux avec un signe d'insertion et le nom d'attribut ne doit pas s'afficher dans le message.

Un modèle défini comme:

class Item < ApplicationRecord
  validates :name, presence: true
end

avec le en.yml suivant:

en:
  activerecord:
    errors:
      models:
        item:
          attributes:
            name:
              blank: "^You can't create an item without a name."

item.errors.full_messages affichera:

You can't create an item without a name

au lieu du Name You can't create an item without a name habituel

10
Rystraum

Voici un autre moyen:

Si vous utilisez ce modèle:

<% if @thing.errors.any? %>
  <ul>
    <% @thing.errors.full_messages.each do |message| %>
      <li><%= message %></li>
    <% end %>
  </ul>
<% end %>

Vous pouvez écrire votre propre message personnalisé comme ceci:

class Thing < ActiveRecord::Base

  validate :custom_validation_method_with_message

  def custom_validation_method_with_message
    if some_model_attribute.blank?
      errors.add(:_, "My custom message")
    end
  end

De cette manière, en raison du trait de soulignement, le message complet devient "Mon message personnalisé", mais l'espace supplémentaire au début est imperceptible. Si vous ne voulez vraiment pas cet espace supplémentaire au début, ajoutez simplement la méthode .lstrip.

<% if @thing.errors.any? %>
  <ul>
    <% @thing.errors.full_messages.each do |message| %>
      <li><%= message.lstrip %></li>
    <% end %>
  </ul>
<% end %>

La méthode String.lstrip supprimera l'espace supplémentaire créé par ': _' et laissera tous les autres messages d'erreur inchangés.

Ou mieux encore, utilisez le premier mot de votre message personnalisé comme clé:

  def custom_validation_method_with_message
    if some_model_attribute.blank?
      errors.add(:my, "custom message")
    end
  end

Maintenant, le message complet sera "Mon message personnalisé" sans espace supplémentaire.

Si vous souhaitez que le message complet commence par un mot en majuscule tel que "l'URL ne peut être vide", vous ne pouvez pas le faire. Au lieu de cela, essayez d’ajouter un autre mot comme clé:

  def custom_validation_method_with_message
    if some_model_attribute.blank?
      errors.add(:the, "URL can't be blank")
    end
  end

Maintenant, le message complet sera "L'URL ne peut pas être vide"

7
Cruz Nunez

Il suffit de le faire de manière normale:

validates_presence_of :email, :message => "Email is required."

Mais affichez-le comme ceci à la place

<% if @user.errors.any? %>
  <% @user.errors.messages.each do |message| %>
    <div class="message"><%= message.last.last.html_safe %></div>
  <% end %>
<% end %>

Résultats

"Email is required."

La méthode de localisation est certainement le moyen "approprié" de le faire, mais si vous faites un petit projet non global et que vous voulez aller vite - c'est vraiment plus facile que de parcourir des fichiers. 

Je l'aime pour la possibilité de mettre le nom du champ ailleurs que le début de la chaîne:

validates_uniqueness_of :email, :message => "There is already an account with that email."
6
brittohalloran

Une solution pourrait être de changer le format d'erreur par défaut d'i18n:

en:
  errors:
    format: "%{message}"

La valeur par défaut est format: %{attribute} %{message}

5
cappie013

Si vous voulez tous les lister dans une liste de Nice mais sans utiliser le nom sympathique et non humain, vous pouvez le faire.

object.errors.each do |attr,message|
  puts "<li>"+message+"</li>"
end
2
adam

À votre avis

object.errors.each do |attr,msg|
  if msg.is_a? String
    if attr == :base
      content_tag :li, msg
    elsif msg[0] == "^"
      content_tag :li, msg[1..-1]
    else
      content_tag :li, "#{object.class.human_attribute_name(attr)} #{msg}"
    end
  end
end

Lorsque vous souhaitez remplacer le message d'erreur sans le nom de l'attribut, ajoutez simplement ^ comme suit le message:

validates :last_name,
  uniqueness: {
    scope: [:first_name, :course_id, :user_id],
    case_sensitive: false,
    message: "^This student has already been registered."
  }
1
luckyruby

Voici mon code qui peut vous être utile si vous en avez encore besoin: Mon modèle: 

validates :director, acceptance: {message: "^Please confirm that you are a director of the company."}, on: :create, if: :is_director?

Ensuite, j'ai créé un assistant pour afficher les messages: 

module ErrorHelper
  def error_messages!
    return "" unless error_messages?
    messages = resource.errors.full_messages.map { |msg|
       if msg.present? && !msg.index("^").nil?
         content_tag(:p, msg.slice((msg.index("^")+1)..-1))
       else
         content_tag(:p, msg)
       end
    }.join

    html = <<-HTML
      <div class="general-error alert show">
        #{messages}
      </div>
    HTML

    html.html_safe
  end

  def error_messages?
    !resource.errors.empty?
  end
end
0

J'ai essayé de suivre, a travaillé pour moi :)

1 job.rb

class Job < ApplicationRecord
    validates :description, presence: true
    validates :title, 
              :presence => true, 
              :length => { :minimum => 5, :message => "Must be at least 5 characters"}
end

2 jobs_controller.rb

def create
      @job = Job.create(job_params)
      if @job.valid?
        redirect_to jobs_path
      else
        render new_job_path
      end     
    end

3 _form.html.erb 

<%= form_for @job do |f| %>
  <% if @job.errors.any? %>
    <h2>Errors</h2>
    <ul>
      <% @job.errors.full_messages.each do |message|%>
        <li><%= message %></li>
      <% end %>  
    </ul>
  <% end %>
  <div>
    <%= f.label :title %>
    <%= f.text_field :title %>
  </div>
  <div>
    <%= f.label :description %>
    <%= f.text_area :description, size: '60x6' %>

  </div>
  <div>
    <%= f.submit %>
  </div>
<% end %> 
0
Aigul

Une approche unique que je n'ai jamais vue mentionnée!

La seule façon dont j'ai pu obtenir toute la personnalisation que je souhaitais était d'utiliser un rappel after_validation pour me permettre de manipuler le message d'erreur.

  1. Pour que le message de validation soit créé normalement, vous n'avez pas besoin d'essayer de le modifier dans l'aide à la validation.

  2. créez un callback after_validation qui remplacera ce message de validation dans le back-end avant qu’il n’atteigne la vue.

  3. Dans la méthode after_validation, vous pouvez faire ce que vous voulez avec le message de validation, comme une chaîne normale! Vous pouvez même utiliser des valeurs dynamiques et les insérer dans le message de validation.


#this could be any validation
validates_presence_of :song_rep_xyz, :message => "whatever you want - who cares - we will replace you later"

after_validation :replace_validation_message

def replace_validation_message
    custom_value = #any value you would like
    errors.messages[:name_of_the_attribute] = ["^This is the replacement message where 
    you can now add your own dynamic values!!! #{custom_value}"]
end

La méthode after_validation aura une portée beaucoup plus grande que l'assistant de validation Rails intégré. Vous pourrez donc accéder à l'objet que vous validez comme vous essayez de le faire avec object.file_name. Ce qui ne fonctionne pas dans l'assistant de validation où vous essayez de l'appeler.

Remarque: nous utilisons le ^ pour supprimer le nom de l'attribut au début de la validation, comme l'a indiqué @Rystraum en faisant référence à ce gem

0
Sami Birnbaum

Si vous travaillez avec Rails-5, vous pouvez également utiliser les éléments suivants:

valide: nom d'utilisateur, présence: true, unicité: {message: "le nom d'utilisateur existe déjà."}

0
Ankit Varshney