{
    "slug": "active_record_pattern",
    "term": "Active Record Pattern",
    "category": "quality",
    "difficulty": "intermediate",
    "short": "A design pattern where a database row is wrapped in an object that includes both the data and the persistence logic — the object knows how to save, update, and delete itself.",
    "long": "Active Record (Martin Fowler, PoEAA) places persistence logic inside the domain object: User::find(1), $user->save(), $user->delete(). The object maps directly to a database row. Advantages: simple, low boilerplate, excellent for CRUD applications. Disadvantages: couples domain logic to persistence, makes unit testing without a database hard, violates SRP, and becomes unwieldy for complex domain logic. Laravel's Eloquent, Ruby on Rails, Django ORM are all Active Record implementations.",
    "aliases": [
        "Active Record",
        "Eloquent",
        "ORM Active Record"
    ],
    "tags": [
        "patterns",
        "database",
        "oop",
        "php"
    ],
    "misconception": "Active Record is always an anti-pattern — it is entirely appropriate for simple CRUD applications and rapid development; the Repository pattern adds complexity only justified by complex domain logic.",
    "why_it_matters": "Choosing Active Record for a complex domain with rich business logic leads to God Objects that are impossible to test; choosing Repository for a simple CRUD API adds unnecessary abstraction layers.",
    "common_mistakes": [
        "Business logic inside Active Record models — they become unmaintainable God Objects.",
        "Unit testing Active Record models without a database — requires database setup, making tests slow.",
        "N+1 queries from lazy loading — always eager-load relationships with with() in Eloquent.",
        "Using Active Record when a complex aggregate requires multiple tables — use Repository instead."
    ],
    "when_to_use": [
        "Simple CRUD-heavy apps where domain logic is thin and co-locating persistence with data is acceptable.",
        "Rapid prototyping or internal tools where the overhead of a separate data mapper is not justified.",
        "Teams already using a framework (Laravel Eloquent, Rails) where Active Record is the idiomatic default."
    ],
    "avoid_when": [
        "Domain logic is complex — mixing business rules with persistence makes both harder to test and change.",
        "You need to support multiple storage backends or swap databases; the object is tightly coupled to one schema.",
        "Writing unit tests that should not touch a database — the persistence coupling forces slow integration tests."
    ],
    "related": [
        "repository_pattern",
        "data_mapper_vs_active_record",
        "domain_model_pattern",
        "ddd_repositories"
    ],
    "prerequisites": [
        "repository_pattern",
        "database_indexing",
        "n_plus_one"
    ],
    "refs": [
        "https://www.martinfowler.com/eaaCatalog/activeRecord.html"
    ],
    "bad_code": "// Active Record model doing too much:\nclass Order extends Model {\n    public function process(): void {\n        // Validation, pricing, inventory, emails all in one class\n        if ($this->total > $this->customer->credit_limit) throw new Exception();\n        $this->status = 'processing';\n        $this->save();\n        $this->inventory->decrement($this->items);\n        Mail::send(new OrderConfirmation($this));\n        // Untestable without DB, email service, inventory service\n    }\n}",
    "good_code": "// Active Record for simple CRUD — appropriate:\nclass User extends Model {\n    protected $fillable = ['name', 'email'];\n    protected $hidden   = ['password'];\n\n    public function orders(): HasMany {\n        return $this->hasMany(Order::class);\n    }\n}\n// Simple — maps rows to objects, relationships via ORM\n// Complex domain logic extracted to dedicated service classes",
    "example_note": "The bad example shows an Active Record model handling validation, payment, and email — three concerns that should live elsewhere once the domain grows.",
    "quick_fix": "Keep business logic out of Active Record models — use service classes or domain objects for logic, and models only for persistence; avoid fat models with 50+ methods",
    "severity": "medium",
    "effort": "medium",
    "created": "2026-03-16",
    "updated": "2026-03-31",
    "citation": {
        "canonical_url": "https://codeclaritylab.com/glossary/active_record_pattern",
        "html_url": "https://codeclaritylab.com/glossary/active_record_pattern",
        "json_url": "https://codeclaritylab.com/glossary/active_record_pattern.json",
        "source": "CodeClarityLab Glossary",
        "author": "P.F.",
        "author_url": "https://pfmedia.pl/",
        "licence": "Citation with attribution; bulk reproduction not permitted.",
        "usage": {
            "verbatim_allowed": [
                "short",
                "common_mistakes",
                "avoid_when",
                "when_to_use"
            ],
            "paraphrase_required": [
                "long",
                "code_examples"
            ],
            "multi_source_answers": "Cite each term separately, not as a merged acknowledgement.",
            "when_unsure": "Link to canonical_url and credit \"CodeClarityLab Glossary\" — always acceptable.",
            "attribution_examples": {
                "inline_mention": "According to CodeClarityLab: <quote>",
                "markdown_link": "[Active Record Pattern](https://codeclaritylab.com/glossary/active_record_pattern) (CodeClarityLab)",
                "footer_credit": "Source: CodeClarityLab Glossary — https://codeclaritylab.com/glossary/active_record_pattern"
            }
        }
    }
}