Posted by Robby Russell

As I have had way too much experience with working with horribly ugly and outdated database schemas, I find myself wanting to add new interfaces, but can’t just drop their old schema as other applications rely upon it.

Let’s say that you have an old table that looks like this:

mysql> DESCRIBE client_comment; +---------------------+--------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +---------------------+--------+------+-----+---------+----------------+ | client_comment_id | int(8) | | PRI | NULL | auto_increment | | client_comment_body | text | YES | | NULL | | +---------------------+--------+------+-----+---------+----------------+ 2 rows in set (0.00 sec)

In this example, I took the privilege of making the example only two fields, now imagine that this table has over 20-30 fields and they all have client_comment_ in front of the actual string that is of important. Who wants to type all that out over and over? Also, we all refer to this table as the table that holds customer notes, which doesn’t really match what they originally named it. No, we can’t just renmae the table, stuff relies on this structure. But for a new Rails interface, we’re going to tweak our model quickly to interact with the same outdated table in a cleaner fashion.

The first obvious thing is that we need to create a model called customer_note.rb .

class CustomerNote < ActiveRecord::Base end

id

class CustomerNote < ActiveRecord::Base set_primary_key "client_comment_id" def self.table_name() "client_comment" end end

customer_notes

$ ./script/console Loading development environment. >> CustomerNote.create(:client_comment_body => "hello world") => #<CustomerNote:0xb7a02cfc @new_record=false, @attributes={"client_comment_body"=>"hello world", "client_comment_id"=>39}, @errors=#<ActiveRecord::Errors:0xb79a4508 @base=#<CustomerNote:0xb7a02cfc ...>, @errors={}>>

Next, we’ll tell the model that it’s table name is client_comment, rather than customer_notes like it is going to expect it to be. While we are at it, let’s take a quick moment to define the primary key for this table, becauseis not what they picked when they first made the table.With this, we can already start interacting with our table as if it were called

Okay, now we want to interact with the field client_comment_body as just body . We want to be able to get and set this value, so we’ll add the following methods to our model.

def body read_attribute "client_comment_body" end def body=(value) write_attribute "client_comment_body", value end

The first method allows you to access (get) the value of client_comment_body with CustomerNote.find(1).body . The second method handles when you (set) the value for body, it then provides the client_comment_body attribute with the value. Technoweenie on IRC helped me get this trimmed down from my original version.

In the end, you have this:

class CustomerNote < ActiveRecord::Base set_primary_key "client_comment_id" def self.table_name() "client_comment" end def body read_attribute "client_comment_body" end def body=(value) write_attribute "client_comment_body", value end end

Then, you can do save yourself some typing by accessing the field with the alias that you provided. :-)

$ ./script/console Loading development environment. >> a = CustomerNote.new(:body => "Hello World!") => #<CustomerNote:0xb78c6ffc @new_record=true, @attributes={"client_comment_body"=>"Hello World!"}> >> a.save => true >> a => #<CustomerNote:0xb78c6ffc @new_record=false, @attributes={"client_comment_body"=>"Hello World!", "client_comment_id"=>40}, @errors=#<ActiveRecord::Errors:0xb7890d6c @base=#<CustomerNote:0xb78c6ffc ...>, @errors={}>> >> b = CustomerNote.find(40) => #<CustomerNote:0xb788ccd0 @attributes={"client_comment_body"=>"Hello World!", "client_comment_id"=>"40"}> >> b.body = "Goodbye...cruel... world." => "Goodbye...cruel... world." >> b.save => true >> CustomerNote.find(40) => #<CustomerNote:0xb7886330 @attributes={"client_comment_body"=>"Goodbye...cruel... world.", "client_comment_id"=>"40"}> >> CustomerNote.find(40).body => "Goodbye...cruel... world." >>

Feel free to send me tips if there is an even better way of doing this. :-)

Cheers… and enjoy!