Help us improve
Share bugs, ideas, or general feedback.
From majestic-rails
Designs Rails apps using layered architecture (Presentation→Application→Domain→Infrastructure). Analyzes violations, plans features, places code, extracts from fat models/controllers.
npx claudepluginhub majesticlabs-dev/majestic-marketplace --plugin majestic-railsHow this skill is triggered — by the user, by Claude, or both
Slash command
/majestic-rails:layered-railsThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
**Audience:** Rails developers working on applications that have outgrown single-file patterns.
Analyzes Rails codebases for layered architecture violations, reviews PRs, plans features and gradual adoption, implements patterns like authorization, view components, and AI integration.
Reviews and refactors Rails apps to Vanilla Rails style: thin controllers, rich domain models, no unnecessary service layers. For PR reviews, codebase analysis, simplification.
Evaluates architecture patterns including simple, MVC, and onion/hexagonal; checks dependency directions; applies YAGNI criteria to avoid premature abstractions.
Share bugs, ideas, or general feedback.
Audience: Rails developers working on applications that have outgrown single-file patterns. Goal: Know which layer code belongs in, when to extract, and which existing skill handles the implementation.
Presentation → Application → Domain → Infrastructure
(HTTP/UI) (Orchestration) (Business) (Persistence/APIs)
Core rule: Lower layers MUST NOT depend on higher layers. Data flows top-to-bottom only.
| Layer | Owns | Does NOT Own |
|---|---|---|
| Presentation | HTTP concerns, params, rendering, channels, mailers | Business logic, direct DB queries |
| Application | Orchestration across models, authorization, form validation | Persistence details, rendering |
| Domain | Business rules, validations, associations, value objects | HTTP context, request objects, Current.* |
| Infrastructure | ActiveRecord, external APIs, file storage, caching | Business rules, presentation |
| Violation | Why It's Wrong | Fix |
|---|---|---|
Current.user in model | Domain depends on presentation context | Pass user as explicit parameter |
request param in service | Application depends on presentation | Extract needed values before calling service |
| Pricing calc in controller | Business logic in presentation | Move to model method or service |
| All logic in services, anemic models | Domain layer is hollow | Keep domain logic in models; services orchestrate |
| Model sends emails directly | Domain depends on infrastructure side-effects | Use callbacks only for data transforms; extract delivery |
Diagnostic for misplaced code:
Example: A User model that handles authentication, avatar processing, notification preferences, and activity logging.
See references/extraction-signals.md for the full methodology.
Rate each callback 1-5. Extract anything scoring 1-2.
| Score | Type | Example | Action |
|---|---|---|---|
| 5 | Transformer | before_validation :normalize_email | Keep |
| 4 | Normalizer | before_save :strip_whitespace | Keep |
| 4 | Utility | after_create :update_counter_cache | Keep |
| 2 | Observer | after_save :notify_admin | Consider extracting |
| 1 | Operation | after_create :send_welcome_email, :provision_account | Extract |
Rule of thumb: If removing the callback would break the model's own data integrity → keep. If it triggers external side-effects → extract.
"Where should this code go?"
| Situation | Pattern | Layer | Skill |
|---|---|---|---|
| Complex multi-model form | Form Object | Presentation | — |
| Request param filtering | Filter Object | Presentation | — |
| View-specific formatting | Presenter / ViewComponent | Presentation | viewcomponent-coder |
| Authorization rules | Policy Object | Application | action-policy-coder |
| Business operation (one-time) | Service / Interaction | Application | active-interaction-coder |
| Multi-model orchestration | Service Object | Application | active-interaction-coder |
| State lifecycle management | State Machine | Domain | aasm-coder |
| Complex reusable query | Query Object | Domain | — |
| Immutable concept (Money, DateRange) | Value Object | Domain | — |
| Shared model behavior | Concern | Domain | — |
| Typed configuration | Config Object | Infrastructure | anyway-config-coder |
| Domain events / audit trail | Event Sourcing | Infrastructure | event-sourcing-coder |
| JSON-backed attributes | Store Model | Domain | store-model-coder |
Is it about HTTP/params/rendering?
YES → Presentation layer
Multi-model form? → Form Object
Filtering params? → Filter Object
Formatting for view? → Presenter or ViewComponent
NO ↓
Is it authorization?
YES → Policy Object (action-policy-coder)
NO ↓
Does it orchestrate multiple models/services?
YES → Application layer
One-time operation? → Service/Interaction (active-interaction-coder)
Needs typed inputs? → ActiveInteraction (active-interaction-coder)
NO ↓
Is it a business rule about a single model?
YES → Domain layer (keep in model or concern)
Has state transitions? → AASM (aasm-coder)
Reusable query? → Query Object
Immutable value? → Value Object
NO ↓
Is it about persistence/external APIs/caching?
YES → Infrastructure layer
app/services/ is a temporary staging area, not a permanent home.
Smell test: If app/services/ has 50+ files and no subdirectories, the waiting room has become permanent storage.
When to extract code from existing locations:
| Signal | Threshold | Action |
|---|---|---|
| Method length | > 15 lines | Extract method or object |
| External API call in model | Any | Extract to service/gateway |
| God object | High churn × high complexity | Decompose (see references/extraction-signals.md) |
| Spec exceeds layer concern | Specification test fails | Extract to appropriate layer |
| Callback score | 1-2/5 | Extract to service or event handler |
| Duplicated query logic | 2+ locations | Extract Query Object |
Current.* in model | Any usage | Pass as explicit parameter |
See references/extraction-signals.md for the complete methodology.
Recommended ordering within model files:
class Order < ApplicationRecord
# 1. Extensions/DSL (has_secure_password, acts_as_*)
# 2. Associations
# 3. Enums
# 4. Normalizations
# 5. Validations
# 6. Scopes
# 7. Callbacks (transformers/normalizers only — score 4-5)
# 8. Delegations
# 9. Public methods
# 10. Private methods
end
This skill complements dhh-coder, not replaces it.
| Situation | Use |
|---|---|
| Small/medium app, standard CRUD | dhh-coder — keep it simple |
| Complex domain, multiple bounded contexts | layered-rails — add structure |
| Authorization beyond simple checks | action-policy-coder via layered guidance |
| Fat model with 500+ lines | layered-rails extraction signals |
| Standard controller actions | dhh-coder — 7 REST actions |
| Multi-step business operation | active-interaction-coder via layered guidance |
Default to simplicity. Reach for layered patterns only when complexity demands it.
Current attributes| Need | Skill |
|---|---|
| Authorization policies | action-policy-coder |
| Typed business operations | active-interaction-coder |
| State machines | aasm-coder |
| Operations + state routing | business-logic-coder |
| ViewComponents | viewcomponent-coder |
| Typed configuration | anyway-config-coder |
| Event sourcing / audit | event-sourcing-coder |
| JSON attributes | store-model-coder |
| Refactoring execution | rails-refactorer |
| DHH-style simplicity | dhh-coder |
| Pattern catalog details | references/pattern-catalog.md |
| Extraction methodology | references/extraction-signals.md |