• 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
    • 🤖 L’IA au service de vos projets numériques
  • 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

Optimiser vos tests avec Cucumber
17 novembre 2025

Optimiser vos tests avec Cucumber

Lire la suite

Comment préparer votre Jira Cloud dès maintenant ? 
14 novembre 2025

Comment préparer votre Jira Cloud dès maintenant ? 

Lire la suite

Replay webinaire IA
5 novembre 2025

Replay webinaire IA

Lire la suite

Atlassian arrête le Data Center : pourquoi votre migration doit commencer maintenant
5 novembre 2025

Atlassian arrête le Data Center : pourquoi votre migration doit commencer maintenant

Lire la suite

Articles associés

Comment préparer votre Jira Cloud dès maintenant ? 
14 novembre 2025

Comment préparer votre Jira Cloud dès maintenant ? 


Lire la suite
Replay webinaire IA
5 novembre 2025

Replay webinaire IA


Lire la suite
Challenge technique inter-agences spécial Halloween
31 octobre 2025

Challenge technique inter-agences spécial Halloween


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
logo 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