active-record-db

This skill should be used when the user asks about Active Record models, database migrations, queries, associations (belongs_to, has_many, has_one, has_and_belongs_to_many), validations, callbacks, scopes, database schema design, SQL optimization, N+1 queries, eager loading, joins, or database-specific features (PostgreSQL, MySQL, SQLite). Also use when discussing ORM patterns, data modeling, or database best practices. Examples:

16 stars

Best use case

active-record-db is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

This skill should be used when the user asks about Active Record models, database migrations, queries, associations (belongs_to, has_many, has_one, has_and_belongs_to_many), validations, callbacks, scopes, database schema design, SQL optimization, N+1 queries, eager loading, joins, or database-specific features (PostgreSQL, MySQL, SQLite). Also use when discussing ORM patterns, data modeling, or database best practices. Examples:

Teams using active-record-db should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/active-record-db/SKILL.md --create-dirs "https://raw.githubusercontent.com/diegosouzapw/awesome-omni-skill/main/skills/development/active-record-db/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/active-record-db/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How active-record-db Compares

Feature / Agentactive-record-dbStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

This skill should be used when the user asks about Active Record models, database migrations, queries, associations (belongs_to, has_many, has_one, has_and_belongs_to_many), validations, callbacks, scopes, database schema design, SQL optimization, N+1 queries, eager loading, joins, or database-specific features (PostgreSQL, MySQL, SQLite). Also use when discussing ORM patterns, data modeling, or database best practices. Examples:

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# Active Record & Databases: Rails ORM Mastery

## Overview

Active Record is Rails' Object-Relational Mapping (ORM) layer. It connects Ruby objects to database tables, providing an elegant API for creating, reading, updating, and deleting data without writing SQL.

Active Record embodies Rails philosophy:
- **Convention over configuration**: Table names, foreign keys, and primary keys follow conventions
- **DRY**: Schema drives model attributes; no redundant declarations
- **Object-oriented**: Work with Ruby objects, not raw SQL
- **Database agnostic**: Same code works with PostgreSQL, MySQL, SQLite

Master Active Record and you master data in Rails applications.

## Models and Conventions

### Basic Model

A model represents a table and provides domain logic:

```ruby
# app/models/product.rb
class Product < ApplicationRecord
  # Table: products
  # Primary key: id
  # Attributes: name, price, description, created_at, updated_at
end
```

Rails infers:
- Table name: `products` (pluralized)
- Primary key: `id`
- Attributes from schema
- Timestamps: `created_at`, `updated_at`

No configuration needed—just convention.

### Naming Conventions

| Element | Convention | Example |
|---------|-----------|---------|
| Model | Singular, CamelCase | `Product`, `LineItem` |
| Table | Plural, snake_case | `products`, `line_items` |
| Foreign key | `model_id` | `user_id`, `category_id` |
| Join table | Alphabetical models | `orders_products` |
| Primary key | `id` | Auto-generated integer |

**Irregular pluralizations** work automatically:
- `Person` → `people`
- `Child` → `children`
- `Octopus` → `octopi`

Rails' inflector handles English pluralization rules.

### Schema Conventions

Special column names have automatic behavior:

- **`id`**: Primary key (auto-generated)
- **`created_at`**: Set when record created
- **`updated_at`**: Updated when record saved
- **`lock_version`**: Optimistic locking counter
- **`type`**: Single Table Inheritance discriminator
- **`{association}_id`**: Foreign key for associations
- **`{association}_type`**: Polymorphic association type

## Migrations

Migrations are Ruby scripts that modify database schema.

### Creating Migrations

```bash
# Generate migration
rails generate migration CreateProducts name:string price:decimal

# Generate model (includes migration)
rails generate model Product name:string price:decimal
```

Generates:

```ruby
# db/migrate/20240115100000_create_products.rb
class CreateProducts < ActiveRecord::Migration[8.0]
  def change
    create_table :products do |t|
      t.string :name
      t.decimal :price, precision: 10, scale: 2

      t.timestamps
    end
  end
end
```

### Running Migrations

```bash
rails db:migrate              # Run pending migrations
rails db:rollback             # Undo last migration
rails db:migrate:status       # Show migration status
rails db:migrate VERSION=20240115100000  # Migrate to specific version
```

### Migration Methods

**Creating tables:**

```ruby
create_table :products do |t|
  t.string :name, null: false
  t.text :description
  t.decimal :price, precision: 10, scale: 2
  t.integer :quantity, default: 0
  t.boolean :available, default: true
  t.references :category, foreign_key: true
  t.timestamps
end
```

**Modifying tables:**

```ruby
change_table :products do |t|
  t.rename :description, :details
  t.change :price, :decimal, precision: 12, scale: 2
  t.remove :quantity
  t.string :sku
  t.index :sku, unique: true
end
```

**Adding columns:**

```ruby
add_column :products, :featured, :boolean, default: false
add_index :products, :name
add_reference :products, :supplier, foreign_key: true
```

**Removing columns:**

```ruby
remove_column :products, :quantity
remove_index :products, :sku
remove_reference :products, :supplier
```

See `references/migrations.md` for comprehensive migration patterns.

## Associations

Associations define relationships between models.

### belongs_to

Declares a one-to-one or many-to-one relationship:

```ruby
class Product < ApplicationRecord
  belongs_to :category
  # Expects: category_id column in products table
  # Provides: product.category
end
```

### has_many

Declares a one-to-many relationship:

```ruby
class Category < ApplicationRecord
  has_many :products
  # Expects: category_id column in products table
  # Provides: category.products
end
```

### has_one

Declares a one-to-one relationship:

```ruby
class User < ApplicationRecord
  has_one :profile
  # Expects: user_id column in profiles table
  # Provides: user.profile
end
```

### has_many :through

Many-to-many with join model:

```ruby
class Order < ApplicationRecord
  has_many :line_items
  has_many :products, through: :line_items
end

class LineItem < ApplicationRecord
  belongs_to :order
  belongs_to :product
end

class Product < ApplicationRecord
  has_many :line_items
  has_many :orders, through: :line_items
end
```

### has_and_belongs_to_many

Many-to-many without join model:

```ruby
class Product < ApplicationRecord
  has_and_belongs_to_many :tags
  # Expects: products_tags join table (no id, no timestamps)
end

class Tag < ApplicationRecord
  has_and_belongs_to_many :products
end
```

### Polymorphic Associations

One model belongs to multiple model types:

```ruby
class Comment < ApplicationRecord
  belongs_to :commentable, polymorphic: true
  # Expects: commentable_type and commentable_id columns
end

class Post < ApplicationRecord
  has_many :comments, as: :commentable
end

class Product < ApplicationRecord
  has_many :comments, as: :commentable
end

# Usage:
post.comments.create(body: "Great post!")
product.comments.create(body: "Love this product!")
```

See `references/associations.md` for advanced association patterns.

## Querying

Active Record provides a rich query interface.

### Finding Records

```ruby
# Find by primary key
Product.find(1)
Product.find([1, 2, 3])

# Find by attributes
Product.find_by(name: "Widget")
Product.find_by!(name: "Widget")  # Raises if not found

# First, last, all
Product.first
Product.last
Product.all
```

### Where Queries

```ruby
# Simple conditions
Product.where(available: true)
Product.where("price < ?", 10)
Product.where("price BETWEEN ? AND ?", 10, 50)

# Hash conditions
Product.where(category_id: [1, 2, 3])
Product.where.not(category_id: 1)

# Ranges
Product.where(created_at: 1.week.ago..Time.now)

# Pattern matching
Product.where("name LIKE ?", "%widget%")
```

### Ordering and Limiting

```ruby
Product.order(created_at: :desc)
Product.order(price: :asc, name: :asc)
Product.limit(10)
Product.offset(20).limit(10)  # Pagination
```

### Selecting Specific Columns

```ruby
Product.select(:id, :name, :price)
Product.select("id, name, UPPER(name) as uppercase_name")
```

### Joining Tables

```ruby
# Inner join
Product.joins(:category)
Product.joins(:category, :tags)

# Left outer join
Product.left_outer_joins(:reviews)

# With conditions
Product.joins(:category).where(categories: { name: "Electronics" })
```

### Eager Loading (N+1 Prevention)

**Problem (N+1 queries):**

```ruby
products = Product.all
products.each do |product|
  puts product.category.name  # Fires query for EACH product!
end
# Fires: 1 query for products + N queries for categories = N+1 queries
```

**Solution (eager loading):**

```ruby
products = Product.includes(:category).all
products.each do |product|
  puts product.category.name  # Uses preloaded data
end
# Fires: 1 query for products + 1 query for categories = 2 queries total
```

Methods:
- `includes`: Preload associations (two queries)
- `eager_load`: Preload with LEFT OUTER JOIN (one query)
- `preload`: Always uses separate queries

### Scopes

Reusable query fragments:

```ruby
class Product < ApplicationRecord
  scope :available, -> { where(available: true) }
  scope :cheap, -> { where("price < ?", 10) }
  scope :expensive, -> { where("price > ?", 100) }
  scope :in_category, ->(category) { where(category: category) }
end

# Usage:
Product.available.cheap
Product.expensive.in_category("Electronics")
```

### Method Chaining

Build complex queries incrementally:

```ruby
products = Product.all

products = products.where(available: true) if params[:available]
products = products.where(category: params[:category]) if params[:category]
products = products.where("price < ?", params[:max_price]) if params[:max_price]

products = products.order(params[:sort] || :created_at)
products = products.page(params[:page])

products  # Execute query when enumerated
```

## Validations

Ensure data integrity before saving.

### Common Validations

```ruby
class Product < ApplicationRecord
  validates :name, presence: true
  validates :price, numericality: { greater_than: 0 }
  validates :sku, uniqueness: true
  validates :email, format: { with: URI::MailTo::EMAIL_REGEXP }
  validates :description, length: { minimum: 10, maximum: 500 }
  validates :category, presence: true
  validates :terms, acceptance: true
end
```

### Conditional Validations

```ruby
validates :coupon_code, presence: true, if: :coupon_used?
validates :shipping_address, presence: true, unless: :pickup?
```

### Custom Validations

```ruby
validate :price_must_be_reasonable

private

def price_must_be_reasonable
  if price.present? && price > 10000
    errors.add(:price, "is unreasonably high")
  end
end
```

### Validation Helpers

```ruby
# Inline validation
product.valid?  # => false
product.errors.full_messages  # => ["Name can't be blank", "Price must be greater than 0"]

# Save with validation
product.save  # => false (doesn't save if invalid)
product.save!  # => raises ActiveRecord::RecordInvalid

# Skip validation (dangerous!)
product.save(validate: false)
```

## Callbacks

Run code at specific points in an object's lifecycle.

### Common Callbacks

```ruby
class Product < ApplicationRecord
  before_validation :normalize_name
  after_validation :log_errors
  before_save :calculate_discount
  after_save :clear_cache
  before_create :generate_sku
  after_create :notify_team
  before_update :track_price_changes
  after_update :reindex_search
  before_destroy :check_orders
  after_destroy :cleanup_images
  after_commit :sync_to_external_system

  private

  def normalize_name
    self.name = name.strip.titleize if name.present?
  end

  def generate_sku
    self.sku = SecureRandom.hex(8).upcase
  end

  def check_orders
    throw :abort if orders.exists?
  end
end
```

### Callback Order

1. `before_validation`
2. `after_validation`
3. `before_save`
4. `before_create` / `before_update`
5. Database operation
6. `after_create` / `after_update`
7. `after_save`
8. `after_commit` / `after_rollback`

### Skipping Callbacks

```ruby
product.update_columns(price: 9.99)  # Skips callbacks and validations
product.update_attribute(:price, 9.99)  # Skips validations only
product.increment!(:view_count)  # Skips validations, runs callbacks
```

## Advanced Patterns

### Single Table Inheritance (STI)

```ruby
class Vehicle < ApplicationRecord
  # type column required
end

class Car < Vehicle
end

class Truck < Vehicle
end

# Queries:
Car.all  # WHERE type = 'Car'
Vehicle.all  # All vehicles
```

### Enums

```ruby
class Order < ApplicationRecord
  enum status: [:pending, :processing, :shipped, :delivered, :cancelled]
end

order = Order.create!(status: :pending)
order.pending?  # => true
order.processing!  # Updates status to processing
order.processing?  # => true

Order.pending  # WHERE status = 0
Order.not_pending  # WHERE status != 0
```

### Composite Primary Keys (Rails 8)

```ruby
class BookOrder < ApplicationRecord
  self.primary_key = [:book_id, :order_id]

  belongs_to :book
  belongs_to :order
end

# Find by composite key
BookOrder.find([book_id, order_id])
```

## Database-Specific Features

### PostgreSQL

```ruby
# JSON columns
add_column :products, :metadata, :jsonb, default: {}

product.metadata = { color: "red", size: "large" }
Product.where("metadata->>'color' = ?", "red")

# Arrays
add_column :products, :tags, :string, array: true, default: []

product.tags = ["electronics", "sale"]
Product.where("? = ANY(tags)", "electronics")

# Full-text search
Product.where("to_tsvector('english', name) @@ to_tsquery(?)", "widget")
```

### MySQL-Specific

```ruby
# Case-insensitive queries (default)
Product.where("name = ?", "Widget")  # Matches "widget", "WIDGET"

# JSON columns (MySQL 5.7+)
add_column :products, :settings, :json
```

## Best Practices

1. **Use scopes** for reusable queries
2. **Eager load** to prevent N+1 queries
3. **Add indexes** for foreign keys and frequently queried columns
4. **Validate** before saving to maintain data integrity
5. **Use transactions** for multi-step operations
6. **Limit callbacks** - keep them simple and focused
7. **Use migrations** - never modify schema directly
8. **Test validations** and associations
9. **Profile queries** - use `explain` to optimize
10. **Use database constraints** (NOT NULL, UNIQUE, FOREIGN KEY)

## Further Reading

For deeper exploration:

- **`references/migrations.md`**: Complete migration guide with patterns
- **`references/associations.md`**: Advanced association techniques
- **`references/query-optimization.md`**: Performance tuning and N+1 prevention

For code examples:

- **`examples/active-record-patterns.rb`**: Common Active Record patterns

## Summary

Active Record provides:
- **Models** that represent database tables
- **Migrations** for schema changes
- **Associations** for relationships
- **Validations** for data integrity
- **Queries** without writing SQL
- **Callbacks** for lifecycle hooks
- **Conventions** that eliminate configuration

Master Active Record, and you master data in Rails.

Related Skills

ADR (Architecture Decision Record)

16
from diegosouzapw/awesome-omni-skill

Create and maintain Architecture Decision Records following a consistent template

ActiveRecord Query Patterns

16
from diegosouzapw/awesome-omni-skill

Complete guide to ActiveRecord query optimization, associations, scopes, and PostgreSQL-specific patterns. Use this skill when writing database queries, designing model associations, creating migrations, optimizing query performance, or debugging N+1 queries and grouping errors.

active-job-coder

16
from diegosouzapw/awesome-omni-skill

Use when creating or refactoring Active Job background jobs. Applies Rails 8 conventions, Solid Queue patterns, error handling, retry strategies, and job design best practices.

active-directory

16
from diegosouzapw/awesome-omni-skill

Query and manage Active Directory: users, groups, computers, OUs, GPO status. Use when user asks about AD objects or domain information.

interactive-portfolio

16
from diegosouzapw/awesome-omni-skill

Expert in building portfolios that actually land jobs and clients - not just showing work, but creating memorable experiences. Covers developer portfolios, designer portfolios, creative portfolios,...

activecampaign-automation

16
from diegosouzapw/awesome-omni-skill

Automate ActiveCampaign tasks via Rube MCP (Composio): manage contacts, tags, list subscriptions, automation enrollment, and tasks. Always search tools first for current schemas.

active-learning-system

16
from diegosouzapw/awesome-omni-skill

Эксперт active learning. Используй для ML с участием человека, uncertainty sampling, annotation workflows и labeling optimization.

active-interleave

16
from diegosouzapw/awesome-omni-skill

Active Interleave Skill

Active Directory Attacks

16
from diegosouzapw/awesome-omni-skill

This skill should be used when the user asks to "attack Active Directory", "exploit AD", "Kerberoasting", "DCSync", "pass-the-hash", "BloodHound enumeration", "Golden Ticket", "Silver Ticket", "AS-REP roasting", "NTLM relay", or needs guidance on Windows domain penetration testing.

active-campaign-automation

16
from diegosouzapw/awesome-omni-skill

Automate ActiveCampaign tasks via Rube MCP (Composio). Always search tools first for current schemas.

running-interactive-commands-with-tmux

16
from diegosouzapw/awesome-omni-skill

Controls interactive CLI tools (vim, git rebase -i, REPLs) through tmux detached sessions and send-keys. Use when running tools requiring terminal interaction, programmatic editor control, or orchestrating Claude Code sessions. Triggers include "interactive command", "vim", "REPL", "tmux", or "git rebase -i".

Proactive Orchestrator

16
from diegosouzapw/awesome-omni-skill

Event-driven orchestrator that chains existing skills, edge functions, and agent capabilities into automated workflows triggered by real-time events. Receives events from webhooks (MeetingBaaS, email, calendar), cron jobs (morning brief, pipeline scan), and Slack interactions (button clicks, approvals), then executes multi-step sequences with context-aware routing, HITL approval gates, and self-invocation for long-running chains. This is the conductor — it connects 30+ existing Slack functions, 6 specialist agents, and the sequence executor into coherent, event-driven sales workflows. NOT triggered by user chat messages. Triggered by system events only.