Handling Tables with Legacy Naming Conventions

Problem

Active Record is designed to work best with certain table and column naming conventions. What happens when you don't get to define the tables yourself? What if you have to work with tables that have already been defined, can't be changed, and deviate from the Rails norm? You want a way to adapt table names and existing primary keys of a legacy database so that they work with Active Record.

Solution

Sometimes you won't have the luxury of designing the database for your Rails application from scratch. In these instances you have to adapt Active Record to deal with existing table naming conventions and use a primary key that isn't named id.

Say you have an existing table containing users named users_2006, defined as follows:

mysql> desc users_2006;
+-----------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+-------------+------+-----+---------+-------+
| username | varchar(50) | NO | PRI | | | 
| firstname | varchar(50) | YES | | NULL | | 
| lastname | varchar(50) | YES | | NULL | | 
| age | int(50) | YES | | NULL | | 
+-----------+-------------+------+-----+---------+-------+
4 rows in set (0.01 sec)

To map objects of an Active Record User class to the users in this table, you must explicitly specify the name of the table that the class should use. To do so, pass the table name to the ActiveRecord::Base::set_table_name method in your class definition:

class User < ActiveRecord::Base
 set_table_name "users_2006"
end

Notice that the users_2006 table has a primary key named username. Because Active Record expects tables with a primary key column named id, you have to specify explicitly which column of the table is the primary key. Here we specify a primary key of username:

class User < ActiveRecord::Base
 set_table_name "users_2006"
 set_primary_key "username"
end

Discussion

The following Rails console session demonstrates how you can interact with the solution's User model without having to know the actual name of the table, or even the name of the primary key column:

>> user = User.new
=> #<User:0x24250e4 @attributes={"lastname"=>nil, "firstname"=>nil, "age"=>nil}, 
 @new_record=true>
>> user.id = "rorsini"
=> "rorsini"
>> user.firstname = "Rob"
=> "Rob"
>> user.lastname = "Orsini"
=> "Orsini"
>> user.age = 35
=> 35
>> user.save
=> true
>> user.attributes
=> {"username"=>"rorsini", "lastname"=>"Orsini", "firstname"=>"Rob", "age"=>35}

Although you can make tables with nonstandard primary keys (i.e., not named id) work with Active Record, there are some drawbacks to doing so. Scaffolding, for example, requires an actual primary key column named id for the generated code to work. If you are relying on the generated scaffolding, you may just want to rename the primary key column to id.