Section 13.3.3 : Associations et validations
🎯 Objectif pédagogique
Maîtriser les associations Active Record (has_many, belongs_to, has_many through) et les validations pour garantir l'intégrité des données.
Les associations : modéliser les relations
Active Record traduit les relations SQL en méthodes Ruby élégantes. Les trois associations les plus courantes :
belongs_to et has_many (One-to-Many)
# Un article appartient à un utilisateur
# Un utilisateur a plusieurs articles
class User < ApplicationRecord
has_many :articles, dependent: :destroy
end
class Article < ApplicationRecord
belongs_to :user
end
# Utilisation
alice = User.find(1)
alice.articles # Tous les articles d Alice
alice.articles.count # Nombre d articles
alice.articles.create(titre: 'Mon premier article')
article = Article.find(1)
article.user # L auteur de l article
article.user.nom # Le nom de l auteur
has_many :through (Many-to-Many)
# Un article a plusieurs tags
# Un tag appartient à plusieurs articles
class Article < ApplicationRecord
has_many :article_tags, dependent: :destroy
has_many :tags, through: :article_tags
end
class Tag < ApplicationRecord
has_many :article_tags, dependent: :destroy
has_many :articles, through: :article_tags
end
class ArticleTag < ApplicationRecord
belongs_to :article
belongs_to :tag
end
# Utilisation
article = Article.find(1)
article.tags # Tous les tags
article.tags << Tag.find_by(nom: 'Ruby') # Ajouter un tag
tag = Tag.find_by(nom: 'Rails')
tag.articles # Tous les articles avec ce tag
has_one
class User < ApplicationRecord
has_one :profil, dependent: :destroy
end
class Profil < ApplicationRecord
belongs_to :user
end
user = User.find(1)
user.profil # Le profil unique
user.create_profil(bio: 'Développeuse Ruby')
Les validations : sécuriser les données
Les validations empêchent les données invalides d'être sauvegardées en base. Elles se déclarent dans le model.
class User < ApplicationRecord
validates :nom, presence: true, length: { minimum: 2, maximum: 50 }
validates :email, presence: true, uniqueness: true,
format: { with: /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i }
validates :age, numericality: { greater_than: 0, less_than: 150 }, allow_nil: true
validates :role, inclusion: { in: %w[admin editor viewer] }
end
# Tester les validations
user = User.new(nom: '', email: 'invalid')
user.valid? # false
user.errors.full_messages
# ["Nom can't be blank", "Email is invalid"]
user.save # false (ne sauvegarde pas)
user.save! # ActiveRecord::RecordInvalid (lève une exception)
# Validations personnalisées
class Article < ApplicationRecord
validate :date_future
private
def date_future
if date_publication.present? && date_publication < Date.today
errors.add(:date_publication, 'doit être dans le futur')
end
end
end
Callbacks : hooks du cycle de vie
class User < ApplicationRecord
before_validation :normaliser_email
after_create :envoyer_email_bienvenue
before_destroy :archiver_donnees
private
def normaliser_email
self.email = email.downcase.strip if email.present?
end
def envoyer_email_bienvenue
UserMailer.welcome(self).deliver_later
end
def archiver_donnees
ArchiveService.archiver(self)
end
end
Que fait dependent: :destroy dans has_many :articles, dependent: :destroy ?
Learn AI, from prompts to agents