Rails: Should I have a separate model for a user profile?

Every case is different. But I’d be wary of ever creating a dedicated model for a UserProfile. It sounds like a very general “throw everything here” type of model. Which is something you should avoid. It’s better to be very specific about the type of data being stored.

Modeling Medium’s user profile

For user profiles, generally the information shown on the profile isn’t exclusive to the users profile.

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

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

(yes, I know Medium doesn’t use Rails, but if they did).

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

Solution: 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).

Create a class that encapsulates all the data you want shown on the profile page.

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

Now if you’re wondering things like, “but my user has a resume on their profile and I want it on the profile page.”

In cases like that, it makes sense to dedicate a model to just that object. Then you’d have a Resume object.

It keeps things very explicit and when other people are working with your code they will know where to look when making changes.