Read my latest article: 8 things I look for in a Ruby on Rails app (posted Thu, 06 Jul 2017 16:59:00 GMT)

The legacy of databases with Rails

Posted by Tue, 26 Jul 2005 03:20:00 GMT

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
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, because id is not what they picked when they first made the table.
class CustomerNote < ActiveRecord::Base

  set_primary_key "client_comment_id" 

  def self.table_name() "client_comment" end

end
With this, we can already start interacting with our table as if it were called 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={}>>

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!

Get help with your Rails project

comments powered by Disqus