• Contenu
  • Bas de page
logo ouidoulogo ouidoulogo ouidoulogo ouidou
  • Qui sommes-nous ?
  • Offres
    • 💻 Applications métier
    • 🤝 Collaboration des équipes
    • 🛡️ Sécurisation et optimisation du système d’information
    • 🔗 Transformation numérique
  • Expertises
    • 🖥️ Développement logiciel
    • ♾️ DevSecOps
    • ⚙️ Intégration de logiciels et négoce de licences
      • Atlassian : Jira, Confluence, Bitbucket…
      • Plateforme monday.com
      • GitLab
      • SonarQube
    • 📚​ Logiciel de CRM et de gestion
    • 🎨 UX/UI design
    • 🌐 Accessibilité Numérique
    • 🗂️​ Démarches simplifiées
    • 📝 Formations Atlassian
  • Références
  • Carrières
    • 🧐 Pourquoi rejoindre Ouidou ?
    • ✍🏻 Nous rejoindre
    • 👨‍💻 Rencontrer nos collaborateurs
    • 🚀 Grandir chez Ouidou
  • RSE
  • Ressources
    • 🗞️ Actualités
    • 🔍 Articles techniques
    • 📖 Livres blancs
    • 🎙️ Interviews Clients
Nous contacter
✕
Git en entreprise
Git en entreprise
19 octobre 2021
Introduction to Project Lombok
Introduction to Project Lombok
26 octobre 2021
Ressources > Articles techniques > Indexer les erreurs sur les sous-objets

Indexer les erreurs sur les sous-objets

Article écrit par Hugo Fabre

Lors du développement d’un projet Rails en mode API uniquement, avec un ou plusieurs clients, il y a quelque chose qui n’est pas forcément facile à gérer, ce sont les erreurs. Aujourd’hui on va se pencher sur un type d’erreur assez spécifique, c’est lorsque vous sauvegardez un objet avec des sous-objets qui peuvent eux aussi être invalides. Prenons un exemple :

# models/order.rb class Order < ApplicationRecord   has_many :order_lines end  # models/order_line.rb class OrderLine < ApplicationRecord   belongs_to :order    validates :quantity, numericality: { greater_than: 0 }   validates :product, presence: true end 

C’est tout ce dont nous avons besoin en termes de code, le reste peut se faire dans une console Rails. Commençons par une situation où tout se passe bien :

order_lines = [OrderLine.new(quantity: 1, product: "controller"), OrderLine.new(quantity: 3, product: "mouse")] # => [#<OrderLine id: nil, product: "controller", quantity: 1, order_id: nil, created_at: nil, updated_at: nil>, #<OrderLine id: nil, product: "mouse", quantity: 3, order_id: nil, created_at: nil, updated_at: nil>]  o = Order.new # => #<Order id: nil, created_at: nil, updated_at: nil>  o.order_lines = order_lines # => [#<OrderLine id: nil, product: "controller", quantity: 1, order_id: nil, created_at: nil, updated_at: nil>, #<OrderLine id: nil, product: "mouse", quantity: 3, order_id: nil, created_at: nil, updated_at: nil>]  o.save # => true  o.errors # => #<ActiveModel::Errors:0x00007f97a15cea78 @base=#<Order id: 1, created_at: "2021-09-10 13:00:54.310420000 +0000", updated_at: "2021-09-10 13:00:54.310420000 +0000">, @errors=[]> 

C’est normal, pas d’erreur à déclarer ici. Passons à un cas en erreur

order_lines = [OrderLine.new(quantity: -2, product: "controller"), OrderLine.new(quantity: 3, product: "mouse")] # => [#<OrderLine id: nil, product: "controller", quantity: -2, order_id: nil, created_at: nil, updated_at: nil>, #<OrderLine id: nil, product: "mouse", quantity: 3, order_id: nil, created_at: nil, updated_at: nil>]  o = Order.new # => #<Order id: nil, created_at: nil, updated_at: nil>  o.order_lines = order_lines # => [#<OrderLine id: nil, product: "controller", quantity: -2, order_id: nil, created_at: nil, updated_at: nil>, #<OrderLine id: nil, product: "mouse", quantity: 3, order_id: nil, created_at: nil, updated_at: nil>]  o.save # => false  o.errors # => #<ActiveModel::Errors:0x00007f97a1d04ab8 @base=#<Order id: nil, created_at: nil, updated_at: nil>, @errors=[#<ActiveModel::Error attribute=order_lines, type=invalid, options={}>]>  o.errors.messages # => {:order_lines=>["is invalid"]} 

Pour expliciter un peu les erreurs des sous-modèles on peut passer par l’utilisation de accepts_nested_attributes_for

On le rajoute dans notre modèle

# models/order.rb class Order < ApplicationRecord   has_many :order_lines   accepts_nested_attributes_for :order_lines end 
o = Order.new # => #<Order id: nil, created_at: nil, updated_at: nil>  o.order_lines = order_lines # => [#<OrderLine id: nil, product: "controller", quantity: -2, order_id: nil, created_at: nil, updated_at: nil>, #<OrderLine id: nil, product: nil, quantity: -3, order_id: nil, created_at: nil, updated_at: nil>]  o.save # => false  o.errors # => #<ActiveModel::Errors:0x00007f979e71cd88 @base=#<Order id: nil, created_at: nil, updated_at: nil>, @errors=[#<ActiveModel::NestedError attribute=order_lines.quantity, type=greater_than, options={:value=>-2, :count=>0}>, #<ActiveModel::NestedError attribute=order_lines.quantity, type=greater_than, options={:value=>-3, :count=>0}>, #<ActiveModel::NestedError attribute=order_lines.product, type=blank, options={}>]>  o.errors.messages # => {:"order_lines.quantity"=>["must be greater than 0", "must be greater than 0"], :"order_lines.product"=>["can't be blank"]} 

C’est déjà mieux, mais comment savoir quelle erreur est assignée à quel sous-objet ? Et bien depuis sa version 5 Rails fourni une option sur has_many : index_errors, et cette option qui porte plutôt bien son nom sert à indexer les erreurs sur une relation has_many. Nous changeons donc notre modèle Order:

# models/order.rb class Order < ApplicationRecord   has_many :order_lines, index_errors: true # On note la nouvelle option   accepts_nested_attributes_for :order_lines end 
order_lines = [OrderLine.new(quantity: -2, product: "controller"), OrderLine.new(quantity: -3, product: nil)] # => [#<OrderLine id: nil, product: "controller", quantity: -2, order_id: nil, created_at: nil, updated_at: nil>, #<OrderLine id: nil, product: nil, quantity: -3, order_id: nil, created_at: nil, updated_at: nil>]  o = Order.new # => #<Order id: nil, created_at: nil, updated_at: nil>  o.order_lines = order_lines # => [#<OrderLine id: nil, product: "controller", quantity: -2, order_id: nil, created_at: nil, updated_at: nil>, #<OrderLine id: nil, product: nil, quantity: -3, order_id: nil, created_at: nil, updated_at: nil>]  o.save # => false  o.errors # => #<ActiveModel::Errors:0x00007f97a125af40 @base=#<Order id: nil, created_at: nil, updated_at: nil>, @errors=[#<ActiveModel::NestedError attribute=order_lines[0].quantity, type=greater_than, options={:value=>-2, :count=>0}>, #<ActiveModel::NestedError attribute=order_lines[1].quantity, type=greater_than, options={:value=>-3, :count=>0}>, #<ActiveModel::NestedError attribute=order_lines[1].product, type=blank, options={}>]>  o.errors.messages # => {:"order_lines[0].quantity"=>["must be greater than 0"], :"order_lines[1].quantity"=>["must be greater than 0"], :"order_lines[1].product"=>["can't be blank"]} 

Et là, en plus d’être expressif, notre client pourra sans problème assigner les messages d’erreur à la bonne ligne.

Je vous laisse avec l’article (en anglais) qui m’a fait découvrir cette option, celle-ci n’étant aujourd’hui pas documentée.

À lire aussi

Fresque numérique miniature image
16 avril 2025

Fresque du Numérique

Lire la suite

intelligence artificielle Ouicommit miniature image
17 mars 2025

Ouicommit – L’intelligence artificielle en entreprise, on y est ! 

Lire la suite

Image miniature Hackathon Women in Tech
13 mars 2025

Hackathon Women in Tech :  un engagement pour une tech plus inclusive 

Lire la suite

image miniature les nouveautés Atlassian
26 février 2025

Les nouveautés Atlassian en 2025

Lire la suite

Articles associés

Fresque numérique miniature image
16 avril 2025

Fresque du Numérique


Lire la suite
intelligence artificielle Ouicommit miniature image
17 mars 2025

Ouicommit – L’intelligence artificielle en entreprise, on y est ! 


Lire la suite
Image miniature Hackathon Women in Tech
13 mars 2025

Hackathon Women in Tech :  un engagement pour une tech plus inclusive 


Lire la suite

À propos

  • Qui sommes-nous ?
  • Références
  • RSE
  • Ressources

Offres

  • Applications métier
  • Collaboration des équipes
  • Sécurisation et optimisation du système d’information
  • Transformation numérique

Expertises

  • Développement logiciel
  • DevSecOps
  • Intégration de logiciels et négoce de licences
  • Logiciel de CRM et de gestion
  • UX/UI design
  • Accessibilité Numérique
  • Démarches simplifiées
  • Formations Atlassian

Carrières

  • Pourquoi rejoindre Ouidou ?
  • Nous rejoindre
  • Rencontrer nos collaborateurs
  • Grandir chez Ouidou

SIEGE SOCIAL
70-74 boulevard Garibaldi, 75015 Paris

Ouidou Nord
165 Avenue de Bretagne, 59000 Lille

Ouidou Rhône-Alpes
4 place Amédée Bonnet, 69002 Lyon

Ouidou Grand-Ouest
2 rue Crucy, 44000 Nantes

Ouidou Grand-Est
7 cour des Cigarières, 67000 Strasbourg

  • Linkedin Ouidou
  • GitHub Ouidou
  • Youtube Ouidou
© 2024 Ouidou | Tous droits réservés | Plan du site | Mentions légales | Déclaration d'accessibilité
    Nous contacter