loading...

Refactoring Tip: Use the View Object pattern in Rails for building a user profile page

mscccc profile image Mike Coutermarsh ・2 min read

Medium.com’s user profile shows all of the users posts, their followers and what they have highlighted.

mediums profile page

I’d imagine their data model works like this. They have a User model, a Post model, a FollowerAssociationModel and a Highlights model.

For their profile page, they bring in data from several different sources.

When building out a users profile page in your app, it might feel tempting to create an entirely new model for it. But I'm generally very wary of creating a model for something so non-specific. It can quickly become a general "throw everything here" model.

Use the View Object Pattern

The best way I have found to do this in Rails is to use the View Object Pattern (aka Presenter Object). You can read more about it here: 7 Patterns to Refactor Fat ActiveRecord Models (search view object).

First, you'd create a class that encapsulates all the data you want shown on the profile page.

Something like this:

class UserProfile
  attr_reader :user

  def initialize(user)
    @user = user
  end

  def tagline
    # example of some html conversion
    @tagline ||= ConvertTagsToLinks.run(user.tagline)
  end

  def posts
    @posts ||= user.posts.order_by_featured_date
  end

  def followers
    @follows ||= user.followers.ordered_by_popularity
  end

  ## ect...
end

(a bit of a contrived example, but hopefully you get the idea)

Then this makes it really easy to have one nice clean object to access in your controllers and views.

# some controller
def show
  @user = User.find(params[:id)
  @user_profile = UserProfile.new(@user)

  # render a view...
end

Then in your view, you are able to easily access your view object.

<p class="tagline"><%= @user_profile.tagline %></p>

Using this pattern keeps your abstractions very explicit. This pattern is easy to write tests for and helps keep User Profile code out of your models.

Give it a try and let me know how it works out for you.

Posted on May 14 '17 by:

Discussion

markdown guide
 

One thing that always made me uncomfortable with this pattern is that it almost always forward SQL read requests to the view. It’s during the rendering of your partial / template that the methods are called.

How do you handle this in production @github? Eager loading in the controller won’t help here because scopes always fire an SQL request I guess.

But the pattern is great, used it multiple times and will use it again. Great article 👍🏼