Open-source project
amatsuda/active_decorator avatar
amatsuda/active_decorator

ActiveDecorator decorates Rails models by convention, in the view only

ORM agnostic truly Object-Oriented view helper for Rails 4, 5, 6, 7, and 8

1,130 stars108 forksRubyMIT

At a glance

What is it?
ActiveDecorator is a Ruby gem that mixes a decorator module into a model automatically when the model reaches a view, so presentation methods live on the object without touching the model class. The convention is the whole mechanism, and it buys the reader clean view templates at the cost of an implicit rule that only applies inside Action View.
Who is it for?
ActiveDecorator fits Rails applications that want view formatting to live on the model object without a presenter layer and without touching controller code, and it does not fit codebases where model behaviour must be identical in every context, or where a decorator naming convention is unwelcome.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly Ruby, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A decorator module that only exists in the view context

ActiveDecorator is a small gem for Rails that keeps helpers and views object-oriented. The idea is that a model such as User has a matching module UserDecorator, and the methods in that module appear on the model instance when, and only when, the instance is used from a view. Nothing changes about the model class itself, and no controller line is edited.

That last point is what makes the gem interesting. The normal Rails way to format a record for display is a helper module that takes the record as an argument, so a template reads something like a long expression with a helper call. ActiveDecorator lets the template call a method on the object instead. The price is that behaviour now depends on where you are standing: inside a view the object answers to the decorator's methods, and outside it does not. The project is explicit that decorators are only mixed in when a model, a collection of models, or an ActiveRecord::Relation is passed from a controller to a view, when partials are rendered with models through :collection, :object or :locals, or when an already decorated model's association is fetched.

The decorator runs in the model's context but can call ActionView helpers

Inside the decorator module, self is the model instance, so any attribute or model method can be called directly. A decorator for an author with first_name and last_name columns defines full_name as a plain string interpolation of those two attributes, with no reference to the record passed in. That is the main ergonomic win: the decorator reads like a method on the object rather than a function that receives it.

The second property is that decorators behave like helpers, so ActionView helper methods such as content_tag or link_to are available inside the module. A BookDecorator can define a link method that calls link_to title, url, and get a fully formed anchor tag without touching a view helper by hand. The trade-off is that a decorator is no longer pure model code, and the project's own note that the decorator module runs in the model's context makes that split obvious: a module that calls link_to cannot be exercised outside a view without extra machinery.

Adding the gem and generating the first decorator

Setup is three steps. The gem is added to the bundle, a decorator module is created for each model, and nothing else needs to change in the existing code. The documentation gives the generator command for a model named user, which produces the conventionally named module:

bash
% rails g decorator user

The naming rule is the mechanism. By default ActiveDecorator looks for a module whose name is the target class name plus the suffix Decorator, so User maps to UserDecorator and Author maps to AuthorDecorator. A decorator for a model User should be named UserDecorator, and because the lookup is by convention, a mismatch means the methods simply are not there at render time rather than raising an error at boot. The whole installation is therefore one gem entry, one generated file per model, and zero edits to controllers.

The gem is MIT licensed, copyright 2011 Akira Matsuda, and the repository has a CHANGELOG.md alongside a Rakefile, a test/ directory and the gemspec. The last push was on 2026-09-22.

A decorator reached from an association inherits the decoration

The second documented example is the one that shows why the gem is more than a view-level wrapper. An Author has_many :books, and a BookDecorator defines a link method. In the view, iterating the author's books yields objects that are already decorated, because the parent instance came through the view context. The template then calls book.link on each one, with no decoration call written by the user.

The mechanism is the second bullet in the feature list: fetching an already decorated Active Record model's association also decorates. This is what removes the usual boilerplate of decorating each element of a collection inside a loop. It also means decoration propagates, and there is no documented switch to stop it, so an association that is fetched deep inside a view gets the same treatment as the root object. If a decorator calls a method that shadows an existing model or association method, that conflict has to be resolved by naming.

run_with carries the view context into background jobs

Formatting a record for a PDF or an email that is generated outside a request cycle is where a view-only decorator falls apart. ActiveDecorator handles this with a run_with method that takes some kind of Action View and a block, and the documented form is:

ruby
ActiveDecorator::ViewContext.run_with ApplicationController.new.view_context do
  ## perform some heavy jobs here
end

The project gives the background task and ActiveJob as the motivating case. Building the view context by hand inside the block is the price of admission, and it is a fairly visible one: the code now knows it is running in a view context, which is exactly what the gem was hiding in the controller-to-view path. The block form is what makes the scope clear, since decoration only applies to what happens inside it.

Testing a decorator without a view at all

Because the decorator is just a module, it can be applied to an instance directly, and that is the approach the project recommends for tests. The API is a singleton on ActiveDecorator::Decorator:

ruby
ActiveDecorator::Decorator.instance.decorate(model_instance)

The RSpec example in the documentation constructs an Organization, decorates it, and asserts on the result:

ruby
describe '#full_name' do
  it 'returns the full organization name' do
    organization = Organization.new(first_name: 'John', last_name: 'Doe')
    decorated_organization = ActiveDecorator::Decorator.instance.decorate(organization)

    expect(decorated_organization.full_name).to eq('John Doe')
  end
end

This is the part of the design that holds up best. A unit test needs no view context, no controller and no rendering, which means the decorator's logic is verified in isolation rather than through a full request. The limitation follows from that same design: the test exercises the module, not the automatic mixing, so the convention itself, the name lookup and the trigger points are only covered by whatever else the project tests.

Changing the suffix when Decorator clashes with your conventions

The convention is configurable through an initializer, and the option is the decorator suffix. The default rule is the target class name plus Decorator, and changing it to Presenter looks like this:

ruby
ActiveDecorator.configure do |config|
  config.decorator_suffix = 'Presenter'
end

That is a small feature with a large blast radius, since the suffix determines which module is found for every model. Teams migrating from another decorator gem, or teams whose models already use a Presenter naming pattern, would set this before generating their first decorator. The documentation does not describe a way to disable automatic decoration for a single model, so the options are the global suffix, or not using the gem for that model.

The alternative approach is worth stating plainly. Instead of decorating by convention, a codebase can keep presentation logic in plain Rails helper modules that receive the record as an argument, or build explicit presenter objects that the controller constructs and passes to the view. Both are more verbose and both are explicit about where the behaviour lives. ActiveDecorator trades that explicitness for templates that read like plain Ruby on the model, and the choice only makes sense if the team accepts that a model's public surface changes depending on the rendering context.

Editorial conclusion

ActiveDecorator fits Rails applications that want view formatting to live on the model object without a presenter layer and without touching controller code, and it does not fit codebases where model behaviour must be identical in every context, or where a decorator naming convention is unwelcome. Before adopting it, check that a decorator suffix configured through ActiveDecorator.configure does not collide with an existing class naming scheme, and confirm that the ActiveDecorator::ViewContext.run_with wrapper is acceptable for the background jobs that need the same formatting. The MIT licence is permissive, but it still requires keeping the copyright notice.

Frequently asked questions

What does ActiveDecorator do?

It mixes a decorator module into a model automatically when the model is passed from a controller to a view, when a partial is rendered with models, or when an already decorated model's association is fetched. The decorator methods are then callable directly on the record in the view.

How do I install ActiveDecorator?

Add the gem to the bundle, then create a decorator module for each model. A generator is provided, run as rails g decorator user, which creates the conventionally named module for the User model.

Which Rails and Ruby versions does ActiveDecorator support?

The supported Rails versions are 4.2.x, 5.0, 5.1, 5.2, 6.0, 6.1, 7.0, 7.1, 7.2, 8.0, 8.1 and 8.2 (edge). Supported Ruby versions run from 2.1.x through 3.4.x plus 4.0.x and 4.1 (trunk).

Can ActiveDecorator be used outside a Rails view?

Yes, for background tasks such as ActiveJob, the project provides ActiveDecorator::ViewContext.run_with, which takes a view context and a block, and decoration applies inside that block. For plain unit tests, ActiveDecorator::Decorator.instance.decorate can be applied to an instance directly.

What licence is ActiveDecorator released under?

The gem is MIT licensed, copyright 2011 Akira Matsuda, with the licence text in MIT-LICENSE in the repository. The project also publishes a CHANGELOG.md and welcomes pull requests.

Official sources

  1. amatsuda/active_decorator on GitHub
  2. Issues
  3. License: MIT
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/amatsuda-active-decorator.svg)](https://hysenlabs.com/projects/amatsuda-active-decorator)