Refacto de la délégation des erreurs dans le UserRdvWizard #4782
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Note
Accrochez-vous avant de lire cette PR de deux lignes mais compliquée :)
Ou alors lisez la en diagonale et faites moi confiance 😇
Contexte
Je m’intéresse aux validations des numéros de pré-demande ANTS cf #4777
Avant de modifier la manière dont sont faites les validations des pré–demandes ANTS je me suis rendu compte que le
UserRdvWizard
est un objet assez étrange et un peu cassé.Problèmes & Solutions
Step2 et Step3
UserRdvWizard::Base
délègue les erreurs à un des deux objets proxied : leRdv
.Pourtant
UserRdvWizard::Step2
etUserRdvWizard::Step3
ne font aucune validation et leur#save
renvoie toujourstrue
.Ce ne sont pas de « vrais » form objects.
J’ai choisi de ne rien changer dans ce refacto mais peut-être qu’on pourrait envisager de sortir Step2 et Step3 et de bien séparer de Base ce qui relève du Form Model et ce qui relève d’un objet utilitaire pour les vues de ce wizard.
Step1
UserRdvWizard::Step1
lui est bien un form object mais un peu étonnant.Il ne définit pas d’
attr_accessor
pour chaque attribut du formulaire.Il définit un
attr_accessor
pour l’objet proxied (ici unUser
).La vue affiche un
form_for(user)
et pas unform_for(user_rdv_wizard)
.Il faut donc que les erreurs soient définies sur le
user
pour être affichées correctement.Pourtant les erreurs sont délèguées au
rdv
parBase
!Cette étape n’affiche pourtant aucun attribut lié au RDV.
C’est probablement un héritage du passé où cette étape contenait des champs du RDV et du user.
Validation numéro de tel côté usagers
La validation de présence du numéro de téléphone est un peu cassée : elle ajoute ses erreurs au
rdv
via la méthode déléguéeBase#errors
.Il y a une validation frontend faite par le navigateur via l’attribut
required
donc en réalité il faut « hacker » pour envoyer un numéro de téléphone vide.Si on contourne ce
required
, la validation est bloquée et l’usager ne peut pas passer à l’étape suivante.Mais aucune erreur n’est affichée car il n’y a aucune erreur sur
user
.J’ai d’abord mis en place une nouvelle feature spec qui échoue pour vérifier que mes modifications corrigent ce souci et empêcher une régression future.
Pour corriger, j’ai supprimé
Base#errors
et implémentéStep1#errors
qui délègue maintenant àuser
.J’ai du déplacer au passage la clé de traduction du
rdv
auuser
.Cette clé de traduction concerne « autant » le rdv que le user puisqu’elle apparait quand un numéro de tel manque au user pour un rdv téléphonique.
La « bonne » place pour cette clé de traduction serait probablement dans un form object si on affichait le formulaire du form object.
Validation numéro ANTS
La validation du numéro de demande ANTS quant à elle ajoute les erreurs directement sur le
user
passé en param.Elles sont donc bien affichées.
Mais il y a aussi besoin d’une ligne
errors.merge!(@user)
qui rappatrie ces erreurs sur lerdv
pour que la validation échoue bien 🤯Si on retire cette ligne :
rdv
passe, donc la ligne suivante passevalid? && @user.update(@user_attributes)
.Ma correction ici aussi c’est le fait d’avoir supprimé
Base#errors
et implémentéStep1#errors
qui délègue maintenant àuser
.On peut alors supprimer sereinement la ligne
errors.merge!(@user)
😅Validation numéro de téléphone côté agents
Au moment de finir cette PR, je me suis rendu compte que mon déplacement de la clé de traduction i18n de l’erreur
missing_for_phone_motif
du modèlerdv
versuser
avait cassé l’affichage d’une erreur similaire côté agent.J’ai commencé par rajouter une spec pour m’assurer que c’était testé car ce n’était pas le cas jusqu’ici, je n’avais reçu aucune alerte que j’avais cassé cette vérification.
Côté agents on fait une vérification légèrement différente : il faut qu’au moins un usager ait un numéro de téléphone.
Le message affiché est pertinent « Aucun usager n’a de numéro de téléphone renseigné alors que le rendez-vous est téléphonique ».
Le problème est qu’on utilisait aussi ce message côté usagers or c’est vraiment peu clair.
Je l’ai remplacé par « Le numéro de téléphone est obligatoire car le RDV aura lieu par téléphone ».
J’ai fait un choix discutable dans ce changement qui est d’inliner le message côté agents plutôt que de passer par les clés de traduction i18n.
Je pense que cela enlève une indirection inutile ici.
J’aurais bien aimé faire de même côté usagers et ne pas passer par i18n mais je ne sais pas comment appeler
errors.add
en lui passant un message inliné plutôt qu’une clé ET en spécifiant que le message d’erreur ne doit pas afficher le nom de l’attribut.J’aimerais faire
errors.add(:phone_number, "Le numéro est obligatoire...", format: "%{message}")
mais ça ne fonctionne pas. J’ai regardé le code de ActiveModel mais je n’ai pas trouvé de façon simple de faire ça 🤷