13 votes

Afficher un lien dans le message d'erreur d'un formulaire Rails

Sur notre formulaire d'inscription, nous validates_uniqueness_of :email

Lorsqu'un utilisateur tente d'utiliser notre formulaire d'inscription et qu'il spécifie une adresse électronique existante, j'aimerais qu'il reçoive un message d'erreur comme celui-ci

Cette adresse électronique est déjà utilisée. Si vous ne parvenez pas à vous connecter, vous pouvez réinitialiser votre mot de passe

J'aimerais évidemment utiliser la route nommée pour le lien, mais mon modèle User n'y a pas accès. Comment puis-je y parvenir ?

Note complémentaire : Nous allons bientôt proposer des traductions pour notre application et tous ces messages d'erreur se retrouveront dans des fichiers YAML. Puis-je d'une manière ou d'une autre injecter mon new_password_url dans un message dans mes fichiers linguistiques YAML (par ex, config/locales/en.yml )

16voto

Elliot Nelson Points 4212

Je sais qu'il s'agit d'une vieille question, mais pour les futurs utilisateurs qui souhaitent insérer un lien dans un message d'erreur, voici quelques conseils qui ont fonctionné pour moi.

Tout d'abord, les messages d'erreur I18n sont déjà supposés être html safe, vous pouvez donc aller de l'avant et écrire un message d'erreur approprié. Dans cet exemple, je modifie le message "email is taken".

# config/locales/en.yml
activerecord:
  errors:
    models:
      user:
        attributes:
          email:
            taken: 'has already been taken. If this is your email address, try <a href="%{link}">logging in</a> instead.'

Remarquez la variable interpolée %link .

Il ne vous reste plus qu'à donner une valeur à cette variable dans votre validateur, comme suit :

# app/models/user.rb
validates :email, :uniqueness => {:link => Rails.application.routes.url_helpers.login_path}

(Par défaut, toutes les options que vous passez ici seront automatiquement envoyées au traducteur I18n sous forme de variables, y compris certaines variables spéciales pré-remplies telles que %value , %model etc.)

C'est tout ! Vous avez maintenant un lien dans votre message d'erreur.

1voto

Eric Hu Points 7388

Il se peut que cela ne corresponde pas aux traductions, mais voici une suggestion :

Dans votre action user_controller#create, enveloppez tout ce que vous avez déjà avec une instruction if. Voici un exemple approximatif :

class UserController < ApplicationController
...

def create
  if User.find(params[:email])
    flash[:alert] = "This email address is in use.  You can ".concat(generate_reset_password_link(params[:email])
    render :action => 'new'
  else
    <your current code>
  end
end

Ensuite, vous devrez écrire une méthode d'aide generate_reset_password_link mais je pense que cela respecte principalement la structure MVC. Le contrôleur est censé s'interfacer avec la vue et le modèle. Cela viole un peu le principe DRY, puisque vous contournez essentiellement la fonction validates_uniqueness_of :email mais vous obtenez un comportement personnalisé. DRY ne me semble pas réalisable à 100% si l'on veut faire des applications plus complexes, mais peut-être pourrez-vous affiner ceci et me prouver que j'ai tort ;)

Il se peut que vous deviez masser un peu pour que les render :action => 'new' se remplit à nouveau avec les données saisies précédemment (au cas où l'utilisateur aurait mal saisi son adresse électronique et qu'elle ne se trouverait pas dans le système).

Si vous décidez d'utiliser cette approche, j'ajouterai un commentaire à la fois le contrôleur et le modèle, ce qui indique que l'unicité de l'email est essentiellement vérifiée à deux endroits. Si quelqu'un d'autre doit regarder ce code, cela l'aidera à le comprendre et à le maintenir.

0voto

Kalendae Points 1354

Vous pouvez placer une balise de votre choix comme ~[new_password_url] dans vos messages d'erreur. Si vous voulez le faire de manière générique, vous pouvez extraire le chemin à l'aide d'une expression rationnelle, puis l'évaluer pour obtenir l'url et l'insérer à nouveau dans le fichier.

0voto

John Douthat Points 28189

Si vous utilisez la version 2.3.x, remplacez votre appel à error_messages avec votre propre aide, écrite dans UsersHelper. Il devrait accepter le FormBuilder ou un objet ActiveRecord et ajuster le message d'erreur comme vous le souhaitez. Vous pouvez faire autant de personnalisations que vous le souhaitez, ou cela peut être aussi simple qu'un gsub :

def user_error_messages(f)
  find_error = "This email address is already in use."
  replacement = "This email address is already in use. #{link_to(...)} to reset your password"
  f.error_messages.sub(find_error, replacement).html_safe
end

Si vous utilisez Rails3, créez une méthode d'aide pour traiter simplement @user.errors.full_messages avant qu'ils ne soient transmis à la vue.

0voto

maček Points 25640

Je suis tombé sur ce document aujourd'hui :

http://api.rubyonrails.org/classes/ActionDispatch/Routing/UrlFor.html

Si vous devez accéder à cette méthode auto-générée à partir d'autres endroits (comme un modèle), vous pouvez le faire en incluant la méthode ActionController::UrlFor dans votre classe :


Étape 1

La sensibilisation aux itinéraires nommés dans le modèle est la partie la plus difficile ; c'est ce qui me permet d'avancer le plus vite.

Je peux maintenant faire quelque chose du genre

class User < ActiveRecord::Base
  include Rails.application.routes.url_helpers

  def reset_password_uri
    new_user_password_path(self)
  end
end

# User.find(1).reset_password_uri => "/users/password/new"

Étape 2

Nous avons donc accès à la route nommée, mais nous devons maintenant l'injecter dans le message YAML.

Voici ce que je viens d'apprendre sur les variables YAML :

# en.yml
en:
  welcome: "Hello, %{username}!"

# es.yml
es:
  welcome: "¡Hola, %{username}!"

Je peux injecter le username en incluant un hachage avec l'élément t méthode

<div id="welcome">
  <%= t :welcome, :username => @user.username %>
</div>

Étape 3

Il ne nous reste plus qu'à trouver un moyen d'ajouter l'interpolation au message d'erreur décrit dans la question initiale. C'est là que je suis actuellement bloqué :(

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X