From activerecord
Guides ActiveRecord in Rails: write migrations, define associations (belongs_to, has_many, through), optimize queries (includes, preload, eager_load), fix N+1 issues, add validations/callbacks, and handle database constraints.
npx claudepluginhub hoblin/claude-ruby-marketplace --plugin activerecordThis skill uses the workspace's default tool permissions.
This skill provides comprehensive guidance for working with ActiveRecord in Rails applications. Use for writing migrations, defining associations, optimizing queries, preventing N+1 issues, implementing validations, and following database best practices.
examples/associations/association_extensions.rbexamples/associations/basic_associations.rbexamples/associations/counter_caches.rbexamples/associations/polymorphic_associations.rbexamples/associations/self_referential.rbexamples/associations/through_associations.rbexamples/basics/crud_operations.rbexamples/basics/dirty_tracking.rbexamples/basics/inheritance.rbexamples/basics/type_casting.rbexamples/callbacks/alternatives_to_callbacks.rbexamples/callbacks/conditional_callbacks.rbexamples/callbacks/lifecycle_callbacks.rbexamples/callbacks/transaction_callbacks.rbexamples/migrations/indexes_and_constraints.rbexamples/migrations/reversible_patterns.rbexamples/migrations/safe_patterns.rbexamples/migrations/schema_changes.rbexamples/querying/batch_processing.rbexamples/querying/eager_loading.rbGuides Next.js Cache Components and Partial Prerendering (PPR) with cacheComponents enabled. Implements 'use cache', cacheLife(), cacheTag(), revalidateTag(), static/dynamic optimization, and cache debugging.
Migrates code, prompts, and API calls from Claude Sonnet 4.0/4.5 or Opus 4.1 to Opus 4.5, updating model strings on Anthropic, AWS, GCP, Azure platforms.
Automates semantic versioning and release workflow for Claude Code plugins: bumps versions in package.json, marketplace.json, plugin.json; verifies builds; creates git tags, GitHub releases, changelogs.
This skill provides comprehensive guidance for working with ActiveRecord in Rails applications. Use for writing migrations, defining associations, optimizing queries, preventing N+1 issues, implementing validations, and following database best practices.
# Create
user = User.create(name: "Alice", email: "alice@example.com")
user = User.create!(...) # Raises on failure
# Read
User.find(1) # Raises RecordNotFound
User.find_by(email: "x") # Returns nil if not found
User.where(active: true) # Returns Relation
# Update
user.update(name: "Bob")
user.update!(...) # Raises on failure
# Delete (callbacks run)
user.destroy
# Delete (no callbacks)
user.delete
| Concept | Purpose |
|---|---|
belongs_to | Child side of association (has foreign key) |
has_many / has_one | Parent side of association |
has_many :through | Many-to-many via join model |
includes / preload | Eager loading (prevent N+1) |
scope | Named query builder |
validates | Model-level data validation |
before_save / after_commit | Lifecycle callbacks |
Need to access associated data?
├── NO → Use `joins` (filtering only)
└── YES → Need to filter/sort by association?
├── NO → Use `preload` (separate queries)
└── YES → Large dataset with many associations?
├── YES → Use `includes` with `references`
└── NO → Use `eager_load` (single JOIN)
| Method | Strategy | Best For |
|---|---|---|
includes | Auto-choose | Default choice |
preload | Separate queries | Large datasets, no filtering |
eager_load | LEFT OUTER JOIN | Filtering by association |
joins | INNER JOIN | Filtering only, not accessing data |
# N+1 problem
Post.all.each { |p| p.author.name } # 1 + N queries
# Solution
Post.includes(:author).each { |p| p.author.name } # 2 queries
Does the rule ALWAYS apply, regardless of business logic?
├── Yes → Database constraint
│ └── Examples: NOT NULL, foreign keys, unique emails
└── No → Model validation
└── Examples: Format rules that change, conditional requirements
Need helpful user-facing error messages?
├── Yes → Model validation (possibly WITH constraint)
└── No → Constraint alone is fine
Best Practice: Use both for critical fields:
# Migration (data integrity)
add_index :users, :email, unique: true
# Model (user feedback)
validates :email, presence: true, uniqueness: true
class Author < ApplicationRecord
has_many :books, dependent: :destroy
has_one :profile
end
class Book < ApplicationRecord
belongs_to :author # Required by default
belongs_to :publisher, optional: true # Allow NULL
end
class Physician < ApplicationRecord
has_many :appointments
has_many :patients, through: :appointments
end
class Appointment < ApplicationRecord
belongs_to :physician
belongs_to :patient
# Join model can have attributes
validates :scheduled_at, presence: true
end
| Option | Purpose |
|---|---|
inverse_of | Required with custom foreign_key |
dependent: :destroy | Cascade delete with callbacks |
counter_cache: true | Cache association count |
touch: true | Update parent's updated_at |
# Always reversible
add_column :users, :name, :string
add_index :users, :email, unique: true
add_reference :orders, :user, foreign_key: true
# Concurrent index (no table lock)
disable_ddl_transaction!
add_index :users, :email, algorithm: :concurrently
remove_column :users, :legacy_field, :string # Include type!
change_column_default :users, :status, from: nil, to: "active"
before_validation → after_validation →
before_save → around_save → before_create →
around_create → [INSERT] → after_create →
after_save → [COMMIT] → after_commit
# WRONG - Race condition!
after_save :enqueue_processing
# CORRECT - Runs after COMMIT
after_commit :enqueue_processing, on: :create
# BAD - loads all records
User.all.each { |u| process(u) }
# GOOD - processes in batches
User.find_each { |u| process(u) }
# Bulk operations
User.where(old: true).in_batches.update_all(archived: true)
includes to prevent N+1 queriesfind_each for processing large datasetspluck(:column) instead of all.map(&:column)inverse_of when using custom foreign_keyafter_commit for background jobs and external APIshas_many :through over has_and_belongs_to_manydefault_scope (causes subtle issues)delete when you need callbacksupdate_column to bypass validations casuallyafter_save for external system interactions| Anti-Pattern | Solution |
|---|---|
| N+1 queries | Use includes, preload, or eager_load |
User.all.map(&:email) | Use User.pluck(:email) |
| Uniqueness without index | Add unique database index |
validates :active, presence: true | Use inclusion: { in: [true, false] } for booleans |
after_save for jobs | Use after_commit |
| Callback hell | Extract to service objects |
default_scope | Use explicit scopes |
has_and_belongs_to_many | Use has_many :through |
For detailed patterns and complete API references, consult:
references/basics.md - Conventions, CRUD, dirty tracking, STI, type castingreferences/migrations.md - Schema changes, indexes, constraints, safe patternsreferences/validations.md - Built-in validators, custom validators, contextsreferences/callbacks.md - Lifecycle hooks, transaction callbacks, alternativesreferences/associations.md - All association types, inverse_of, dependent optionsreferences/querying.md - Finders, eager loading, scopes, batch processingReady-to-use code patterns in examples/:
examples/basics/ - CRUD, dirty tracking, type casting, inheritanceexamples/migrations/ - Schema changes, indexes, safe patterns, reversibilityexamples/validations/ - Built-in, conditional, custom, contexts, constraintsexamples/callbacks/ - Lifecycle, transaction callbacks, conditional, alternativesexamples/associations/ - Basic, through, polymorphic, self-referential, extensionsexamples/querying/ - Finders, eager loading, scopes, batch processing, optimization