We are a software consultancy based in Berlin, Germany. We deliver
high quality web apps in short timespans.

Upstream Agile GmbH

Dealing with legacy databases - multiple models per table

June 04, 2008 by alex

On a recent Rails project I had to use an old database schema that had been designed years ago for some php app. The two main entities in the application were companies and their projects. For whatever reason the designer had created one huge table called organizations with all the companies and projects inside. A row in the database marked a company when the is_company column was 1 and a project when the is_project column was 1.

|----------------------------------------------------|
| id | name                | is_company | is_project |
|----------------------------------------------------|
| 1  | google              | 1          | 0          |
| 2  | world domination    | 0          | 1          |
|----------------------------------------------------|

In my rails app I created two ActiveRecord models: Company and Project and set the table name for both to organizations:

class Company
  set_table_name 'organizations'
end

class Project
  set_table_name 'organizations'
end

Now the real problem was his: when I did a Company.find :all I got all the companies and all the projects, so I had to do this instead: Company.find :all, :conditions => {:is_company => true} - throughout the project, and whenever I forgot the condition somewhere all the projects showed up in the wrong place. So what I needed was a generic solution.

To make a longer story short I played with scope_out defining a projects scope on the Company model, so I could at least do Company.find_all_companies and didn’t have to specify the conditions over and over again - but that still wasn’t DRY at all. One morning short after waking up (the time I usually have the best ideas) it dawned on me how simple the solution actually is:

class Company
  def self.find(*params)
    with_scope(:find => {:conditions => {:is_company => true}}) do
      super
    end
  end

  def self.count(*params)
    with_scope(:find => {:conditions => {:is_company => true}}) do
      super
    end
  end
end

I added a scope around all find and count calls of my model and now I can just do whatever find operations I want and don’t have to think about scopes and tables ever again. Sweet object encapsulation.