Agent skill
rails-model-patterns
Analyzes and recommends ActiveRecord model patterns including associations, validations, scopes, callbacks, migrations, and query optimization. Use when designing models, reviewing schema, adding associations (has_many, belongs_to), writing validations, creating scopes, or planning migrations. NOT for controller logic, routing, view rendering, or service object design.
Install this agent skill to your Project
npx add-skill https://github.com/ag0os/rails-dev-plugin/tree/main/skills/rails-model-patterns
SKILL.md
Rails Model Patterns
Analyze and recommend ActiveRecord model patterns for well-structured Rails applications.
Supporting Documentation
- associations.md - Association decision guidance and advanced patterns
- validations.md - Validation strategy and custom validators
- migrations.md - Safe migration practices for production
- value-objects.md - Value object and Struct/Data patterns
Core Principles
- Organize by convention: Constants, associations, validations, scopes, callbacks, class methods, instance methods
- Database-backed integrity: Always pair ActiveRecord validations with database constraints (unique index, NOT NULL, check constraints)
- Associations always have
:dependent: Prevent orphaned records - Use
:inverse_of: Ensure bidirectional association consistency - Callbacks: Omakase — use freely for simple, predictable side effects ("whenever X happens, do Y"). Service-oriented — minimize; prefer service objects for side effects
Model Structure Template
Follow standard Rails model organization. Key ordering: constants, associations, validations, scopes, callbacks, class methods, instance methods, private methods. Generate standard ActiveRecord associations, validations, and scopes following Rails conventions.
Key Patterns
State as Relationships (not booleans/enums)
Instead of a closed boolean, use a related model. Stores who, when, and why.
class Card < ApplicationRecord
has_one :closure, dependent: :destroy
def closed? = closure.present?
def close!(by:, reason: nil) = create_closure!(creator: by, reason: reason)
def reopen! = closure&.destroy!
end
class Closure < ApplicationRecord
belongs_to :card
belongs_to :creator, class_name: "User"
end
Default Association Values
Reduce controller boilerplate using default: with lambdas:
class Post < ApplicationRecord
belongs_to :creator, class_name: "User", default: -> { Current.user }
belongs_to :account, default: -> { Current.account }
end
# Controller: @post = Post.create!(post_params) — no need to assign creator
Concern-Based Domain Composition (Omakase)
Omakase profile: Concerns are the primary tool for decomposing models — for domain logic, not just shared behavior. Slice by trait/role: Triageable, Postponable, Closeable.
# app/models/concerns/closeable.rb
module Closeable
extend ActiveSupport::Concern
included do
has_one :closure, dependent: :destroy
scope :closed, -> { joins(:closure) }
scope :open, -> { where.missing(:closure) }
end
def closed? = closure.present?
def close!(by:, reason: nil) = create_closure!(creator: by, reason: reason)
def reopen! = closure&.destroy!
end
# app/models/card.rb — composed from concerns
class Card < ApplicationRecord
include Closeable
include Triageable
include Postponable
end
POROs for Domain Operations (Omakase)
Omakase profile: Plain Ruby objects for operations that don't fit a model. Not "service objects" — just objects, often in app/models/.
# app/models/signup.rb
class Signup
include ActiveModel::Model
attr_accessor :name, :email, :password
validates :name, :email, :password, presence: true
def save
return false unless valid?
User.create!(name: name, email: email, password: password)
end
end
Counter Cache with Default Lambda
# migration: add_column :users, :posts_count, :integer, default: 0, null: false
belongs_to :user, counter_cache: true
Anti-Patterns
| Anti-Pattern | Problem | Fix |
|---|---|---|
| Fat models (500+ lines) | Hard to maintain | Omakase: extract concerns. Service-oriented: extract service objects |
| Callbacks with complex orchestration | Hard to reason about | Omakase: keep callbacks simple; use model methods for multi-step workflows. Service-oriented: use service objects |
Missing :dependent on associations |
Orphaned records | Always specify :dependent |
default_scope |
Confusing query behavior | Use named scopes instead |
| Validations without DB constraints | Data integrity gaps | Add both layers |
| Boolean flags for state | No audit trail, no metadata | Use state-as-relationship pattern (Closure, Pin, Triage models) |
Output Format
When analyzing or creating models, provide:
- Model file with proper structure and organization
- Migration file with indexes, constraints, and safe rollback
- Test outline: Omakase — Minitest with fixtures. Service-oriented — RSpec with factories
- Performance notes on indexes and query patterns
Error Handling
- Use
save(returns false) for user-facing forms;save!(raises) inside transactions - Wrap multi-model operations in
ActiveRecord::Base.transaction - Handle
ActiveRecord::RecordInvalid,ActiveRecord::RecordNotFound,ActiveRecord::StaleObjectError - Use optimistic locking (
lock_version) for concurrent updates
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
rails-caching-patterns
Caching patterns for Rails applications including fragment caching, low-level caching, HTTP caching, Russian doll caching, and cache invalidation strategies. Automatically invoked when working with Rails.cache, cache stores, stale?/fresh_when, fragment caching, cache keys, or performance optimization through caching. Triggers on "cache", "caching", "Rails.cache", "fragment cache", "Russian doll", "stale?", "fresh_when", "cache key", "cache store", "Redis cache", "Solid Cache", "memcached", "ETag", "cache invalidation", "cache bust". NOT for CDN configuration (use rails-devops-patterns) or database query optimization (use rails-model-patterns).
rails-graphql-patterns
Analyzes and recommends GraphQL patterns for Rails using graphql-ruby including schema design, types, resolvers, mutations, subscriptions, DataLoader, and query complexity. Use when building GraphQL APIs, defining types, writing mutations, optimizing N+1 queries, or structuring app/graphql. NOT for REST API controllers, ActiveRecord queries outside GraphQL, or Turbo Stream responses.
ruby-object-design
Automatically invoked when making decisions about Ruby code structure and organization. Triggers on "class or module", "should this be a class", "struct vs class", "PORO", "data object", "design pattern", "class vs module", "when to use class", "module vs class", "stateless class", "value object", "data container", "object factory", "extend self", "singleton class". Provides guidance on choosing the right Ruby construct (class, module, Struct, Data, Hash). NOT for code smell identification or refactoring (use ruby-refactoring) or Rails-specific framework patterns.
rails-views-patterns
Analyzes Rails view templates, partials, layouts, helpers, and form patterns for best practices. Use when reviewing ERB templates, improving view performance with fragment caching, fixing form helpers, organizing partials, adding accessibility attributes, or evaluating collection rendering. NOT for Stimulus/Turbo logic (use hotwire-patterns), controller concerns, or API-only responses.
rails-architecture-patterns
Provides architectural planning, design decisions, and coordination guidance for Rails applications. Use when planning new features, choosing between design approaches (STI vs polymorphic, service vs concern, monolith vs engine), evaluating system architecture, or deciding which domain skill or agent to delegate to. NOT for implementation details within a single domain (use the domain-specific skill instead).
rails-mailer-patterns
Action Mailer patterns for Rails applications. Automatically invoked when working with email delivery, mailer classes, email templates, mailer previews, interceptors, or delivery configuration. Triggers on "mailer", "email", "ActionMailer", "deliver_later", "deliver_now", "mail template", "email preview", "SMTP", "SendGrid", "Postmark", "notification email". NOT for push notifications, SMS, or in-app messaging.
Didn't find tool you were looking for?