01 March 2015

Seamless ActiveRecord Model extension

The Problem

What if you have one very bloated model, like User, that has a ton of fields you use only once or twice in your whole application and yet paying price for it every time you fetch / create a new one.

In this case what you want is to move some of these fields to another model (e.g. profile or user details).

The Solution

First step is to generate another model, let's name it UserProfile and link it to User model.

You would also have to run a migration that adds UserProfile to all existing users. Now what you can do is to write something like:

Now, of course, we could stop there, but why miss all the fun? What we want to do instead is:

So how do we do that?

Performance

When I measured how speed and memory footprint correspond to number of columns I found that both increase roughly linear as number of columns grows.

Precautions

When mass-assigning attributes from controller while using CanCan gem (tested in Rails 3.2), e.g. (User.new(params[:user])), CanCan tries to be smart and in "load_and_authorize_resource" tries to clean up all the unknown attributes from params[:user]. Solution is to set @user instance variable before "load_and_authorize_resource" is called.

p.s. in retrospective that blog post has a very ambiguous title, but that's the best I could come up with.

p.p.s. Happy Spring everyone!