Les Anti-Patrons de Rails dans les Modèles – et comment les corriger
Rails encourage la séparation claire des préoccupations, mais il est facile de laisser la logique fuir dans la mauvaise couche. Le modèle est censé encapsuler les règles métier et le comportement du domaine, mais de nombreuses applications se retrouvent avec de gros contrôleurs, des vues extrêmement chargées, ou des modèles trop complexes. Voici ci-dessous les anti-patrons courants dans les modèles Rails et leurs solutions, avec du code.
1. La logique de vue appartient au modèle
Une erreur courante consiste à placer une logique métier conditionnelle directement dans les vues.
Mauvais :
<% if @order.total > 100 %>
<p>Commande Premium</p>
<% end %>
Mieux : Déplacer la règle dans le modèle.
class Order < ApplicationRecord
def premium?
total > 100
end
end
<% if @order.premium? %>
<p>Commande Premium</p>
<% end %>
2. Des callbacks qui en font trop
Les callbacks (rappels) sont utiles, mais en abuser cache un comportement important.
Mauvais :
class User < ApplicationRecord
after_create :send_welcome_email
def send_welcome_email
Mailer.welcome(self).deliver_now
end
end
Mieux : Extraire dans un objet de service.
class UserSignup
def self.call(user)
Mailer.welcome(user).deliver_now
end
end
user = User.create!(params)
UserSignup.call(user)
3. Du SQL dans les contrôleurs
La logique de requête encombre les contrôleurs et disperse les règles métier.
Mauvais :
@active_users = User.where("last_login > ?", 30.days.ago)
Mieux : Utiliser une portée (scope) dans le modèle.
class User < ApplicationRecord
scope :recently_active, -> { where("last_login > ?", 30.days.ago) }
end
@active_users = User.recently_active
4. Attributs sérialisés au lieu de tables
Le déversement de hachages dans les colonnes de type [serialize](https://api.rubyonrails.org/classes/ActiveModel/Serialization.html) rend les requêtes difficiles.
Mauvais :
class User < ApplicationRecord
serialize :preferences, Hash
end
Mieux : Normaliser avec une association.
class Preference < ApplicationRecord
belongs_to :user
end
class User < ApplicationRecord
has_many :preferences
end
5. Abuser de l’héritage d’une seule table (STI)
STI force des sous-classes non liées dans une seule table, souvent avec de nombreuses colonnes NULL.
Mauvais :
class Payment < ApplicationRecord; end
class CreditCardPayment < Payment; end
class BankTransferPayment < Payment; end
Mieux : Utiliser le design polymorphe ou de composition.
class Payment < ApplicationRecord
belongs_to :payable, polymorphic: true
end
class CreditCard < ApplicationRecord
has_many :payments, as: :payable
end
Cet article a été inspiré par le livre Rails AntiPatterns: Best Practice Ruby on Rails Refactoring par Chad Pytel et Tammer Saleh. Si vous souhaitez lire le livre complet, vous pouvez le trouver sur Amazon : Rails AntiPatterns
Si vous achetez le livre via ce lien Amazon, je peux gagner une petite commission sans frais supplémentaires pour vous — merci de soutenir ce contenu.
À retenir
- Déplacez les règles métier vers les modèles (pas dans les vues ni les contrôleurs).
- Utilisez des objets de service lorsque les callbacks cachent trop de choses.
- Gardez le SQL dans les scopes, plutôt que des requêtes dispersées.
- Normalisez les structures de données, évitez les blobs sérialisés.
- Évitez les abus de STI ; préférez une conception polymorphe ou compositionnelle.
En refactorisant ces anti-patrons, vos modèles restent expressifs, vos contrôleurs minces et vos vues propres.