DEV Community

Mayra
Mayra

Posted on

Enterprise Design Patterns: Implementing the Active Record Pattern in Ruby

Enterprise applications power businesses from banks to e-commerce platforms. Building robust, maintainable, and scalable enterprise systems requires not only well-written code but also the right architectural patterns.

One powerful pattern from Martin Fowler’s Catalog of Patterns of Enterprise Application Architecture is the Active Record Pattern. This pattern combines the domain object with data persistence, simplifying CRUD operations and making the code straightforward for smaller domains or prototyping.

What is the Active Record Pattern?
The Active Record Pattern maps an object in the application directly to a row in the database. Each object is responsible for saving, updating, and deleting itself from the database.

Benefits:

  • Easy to understand and implement
  • Encapsulates data access logic within the object
  • Reduces boilerplate code for CRUD operations

Drawback:

  • Can become messy for complex domains where business logic grows

Real-World Example: User Management System in Ruby
We will implement a simple user system where the User object handles its own persistence using the Active Record pattern.

# user.rb
require 'sqlite3'

# Create database connection
DB = SQLite3::Database.new "enterprise.db"
DB.execute <<-SQL
  CREATE TABLE IF NOT EXISTS users (
    id INTEGER PRIMARY KEY,
    name TEXT,
    email TEXT
  );
SQL

class User
  attr_accessor :id, :name, :email

  def initialize(name, email, id=nil)
    @name = name
    @email = email
    @id = id
  end

  def save
    if @id
      DB.execute("UPDATE users SET name=?, email=? WHERE id=?", [@name, @email, @id])
    else
      DB.execute("INSERT INTO users (name, email) VALUES (?, ?)", [@name, @email])
      @id = DB.last_insert_row_id
    end
  end

  def self.find(id)
    row = DB.execute("SELECT * FROM users WHERE id=?", id).first
    row ? User.new(row[1], row[2], row[0]) : nil
  end

  def self.all
    DB.execute("SELECT * FROM users").map { |row| User.new(row[1], row[2], row[0]) }
  end

  def delete
    DB.execute("DELETE FROM users WHERE id=?", @id) if @id
  end
end

Enter fullscreen mode Exit fullscreen mode

Demo

# main.rb
require_relative 'user'

# Create users
alice = User.new("Alice", "alice@example.com")
alice.save

bob = User.new("Bob", "bob@example.com")
bob.save

# List all users
puts "All users:"
User.all.each { |user| puts "#{user.id}: #{user.name} (#{user.email})" }

# Find and update user
user = User.find(1)
user.name = "Alice Smith"
user.save

# Delete a user
User.find(2).delete

puts "After updates:"
User.all.each { |user| puts "#{user.id}: #{user.name} (#{user.email})" }

Enter fullscreen mode Exit fullscreen mode

Expected Output:
All users:
1: Alice (alice@example.com)
2: Bob (bob@example.com)
After updates:
1: Alice Smith (alice@example.com)

Why Active Record Helps

  • Encapsulation: Each object handles its own persistence
  • Simplicity: Easy to implement for small applications or prototypes
  • Readability: CRUD operations are directly visible on the object

For more complex systems, patterns like Repository or Unit of Work might be better, but Active Record is excellent for quick development and simple domains.

Conclusion
The Active Record Pattern is a practical enterprise design pattern for managing domain objects with integrated persistence. By using Ruby, we demonstrated a user management system where objects can save, update, and delete themselves, making the code readable, maintainable, and easy to extend.

Top comments (0)