DEV Community

Mike Coutermarsh
Mike Coutermarsh

Posted on

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

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
Enter fullscreen mode Exit fullscreen mode

(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
Enter fullscreen mode Exit fullscreen mode

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

<p class="tagline"><%= @user_profile.tagline %></p>
Enter fullscreen mode Exit fullscreen mode

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.

Top comments (1)

Collapse
 
toommz profile image
Thomas

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 👍🏼