---
title: Decorating ActiveRecord
teaser: Avoid some tricky edge cases when decorating ActiveRecord models.
tags: web,ruby,rails
author: Joël Quenneville
published_on: 2017-03-31
---

It's common to use the [decorator/presenter] pattern to wrap `ActiveRecord`
objects and add view-specific logic.

For example:

```ruby
class Profile < SimpleDelegator
  def title
    "#{first_name} #{last_name}'s profile"
  end
end
```

In the controller, you'd say something like:

```ruby
class ProfilesController < ApplicationController
  def show
    @profile = Profile.new(current_user)
  end
end
```

And in the view:

```erb
<h1><%= profile.title %></h1>
```

## Things fall apart

Simple enough. Now let's look at some examples that leverage
[`to_partial_path`].

Given this decorator:

```ruby
class Profile < SimpleDelegator
  def to_partial_path
    "profiles/profile"
  end
end
```

What happens in this view?

```erb
<%= render profile %>
```

It will **not** render the `profiles/profile` partial but will instead render
the `users/user` partial. What happened?

## Becoming a model

The Rails rendering code has a conditional that looks like this (simplified):

```ruby
if object.responds_to?(:to_model)
  path = object.to_model.to_partial_path
else
  path = object.to_partial_path
end
```

For most objects where you define `to_partial_path`, the rendering code will
take that second branch and just call `to_partial_path` on your object.

However, decorated `ActiveRecord` objects _do_ respond to `to_model` so the
rendering will take that first branch. What happens when you call `to_model` on
a decorator?

It delegates to the wrapped user's implementation which returns itself. This
means calling `to_model` on the decorator returns the _unwrapped user_.

```ruby
[1] pry(main)> profile = Profile.new(User.new)
=> #<User:0x007f82da2e1d28>
[2] pry(main)> profile.class
=> Profile
[3] pry(main)> profile.to_model.class
=> User
```

This all means that `User#to_partial_path` gets invoke rather than
`Profile#to_partial_path`.

The solution is to define `to_model` on the decorator:

```ruby
class Profile < SimpleDelegator
  def to_model
    self
  end

  # other things
end
```

## A matter of form

So all you need to do is define `to_model` on your decorator? Not so fast! Rails
has some other surprises up its sleeve.

How about something like this:

```erb
<%= form_for Profile.new(User.new) do |f| %>
<% end %>
```

You might expect this form to POST to `/profiles` but instead it will submit
to `/users`. Isn't the path based on the class name? Apparently not. Instead the
URL is built based on attributes of your object's `model_name`. Since
`model_name` is delegated to the underlying user, the form submits to `/users`.

```ruby
[1] pry(main)> profile = Profile.new(User.new)
=> #<User:0x007fc678898780>
[2] pry(main)> profile.model_name.route_key
=> "users"
```

This can be fixed by extending `ActiveModel::Naming` (which defines
`model_name`):

```ruby
class Profile < SimpleDelegator
  extend ActiveModel::Naming
end
```

Now it's generating paths for "profiles" instead of "users".

```ruby
[7] pry(main)> profile = Profile.new(User.new)
=> #<User:0x007fc6805005e8>
[9] pry(main)> profile.model_name.route_key
=> "profiles"
```

## Playing nicely with ActiveRecord and ActiveModel

If you're decorating an `ActiveRecord` or `ActiveModel` object in Rails, you
probably want to define the following to ensure the decorator works the way you
expect instead of silently delegating to the underlying object:

```ruby
class Profile < SimpleDelegator
  extend ActiveModel::Naming

  def to_model
    self
  end
end
```

[decorator/presenter]: https://thoughtbot.com/blog/evaluating-alternative-decorator-implementations-in
[`to_partial_path`]: https://thoughtbot.com/blog/rendering-collections-in-rails
