This skill should be used when the user asks to "create a decorator", "write a decorator", "move logic into decorator", "clean logic out of the view", "isn't it decorator logic", "test a decorator", or mentions Draper, keeping views clean, or representation logic in decorators. Should also be used when editing *_decorator.rb files, working in app/decorators/ directory, questioning where formatting methods belong (models vs decorators vs views), or discussing methods like full_name, formatted_*, display_* that don't belong in models. Provides guidance on Draper gem best practices for Rails applications.
View on GitHubFebruary 1, 2026
Select agents to install to:
npx add-skill https://github.com/hoblin/claude-ruby-marketplace/blob/main/plugins/draper/skills/draper-decorators/SKILL.md -a claude-code --skill draper-decoratorsInstallation paths:
.claude/skills/draper-decorators/# Draper Decorators for Rails
This skill provides guidance for creating effective Draper decorators in Rails applications.
## Philosophy
Decorators implement separation of concerns between **business logic** (models) and **presentation logic** (views). A decorator wraps a model to add view-specific methods without polluting the model.
**What belongs in decorators:**
- Date/time formatting (`created_at.strftime("%B %d, %Y")`)
- String concatenation (`"#{first_name} #{last_name}"`)
- HTML generation (`h.content_tag(:span, status, class: css_class)`)
- Conditional rendering based on state
- Number formatting (currency, percentages)
- CSS class generation based on object state
**What does NOT belong in decorators:**
- Business logic (validations, calculations, state changes)
- Database queries (use includes in controllers)
- Anything not directly related to presentation
## Basic Structure
```ruby
# app/decorators/user_decorator.rb
class UserDecorator < ApplicationDecorator
delegate_all
def full_name
"#{first_name} #{last_name}"
end
def formatted_created_at
created_at.strftime("%B %d, %Y")
end
def status_badge
css_class = active? ? "badge-success" : "badge-secondary"
h.content_tag(:span, status, class: "badge #{css_class}")
end
end
```
## Delegation Strategies
### Option 1: `delegate_all` (Convenient)
Delegates all methods to the wrapped object via `method_missing`. Use for most decorators.
```ruby
class ProductDecorator < ApplicationDecorator
delegate_all
def formatted_price
h.number_to_currency(price)
end
end
```
### Option 2: Explicit Delegation (Strict)
Explicitly declare which methods to delegate. Use for larger apps where control matters.
```ruby
class ProductDecorator < ApplicationDecorator
delegate :id, :name, :price, :created_at, :persisted?
def formatted_price
h.number_to_currency(price)
end
end
```
## Accessing the Wrapped Object
Three equivalent ways to access the model:
```ruby
class Art