ActiveRecord : Building a Rails application based a legacy database



Written by Anthony Heukmes on Fri Feb 20 15:45:30 UTC 2009

2 comments



In a perfect world, a new data schema is created with a new Rails application. The database evolves with the application and will respect all the ActiveRecord conventions.
It is the ideal case because no configuration is required and you can fully benefit of migrations.
The development speed reaches his maximum.

But legacy databases are everywhere in professional environments.
A big Oracle schema which doesn't respect any ActiveRecord convention and that you cannot modify because other applications are already based on it.
The only thing you can do is create views in your schema and it is often very useful. But it's not enough.

Does that mean you have to forget about Rails and come back to Java development? Fortunately, the answer is no! :-)

As you already know, a schema is "compatible" with ActiveRecord if he follows a few conventions. So the name of the table must be the pluralized name of the model (User -> Users)
and your primary key must be an auto-incremented value called ID.
The MUST verb is however not right here. If you follow the conventions, you will not have to configure your model, the mapping between your Ruby object and your table will be done automatically. But if the conventions are not respected, you'll always have the possibility to configure the mapping yourself.

Let's take the following schema :



It clearly doesn't follow the ActiveRecord conventions. The name of the "my_users" table should be "users", and the primary key should be "id" instead of "my_pk."

I'm working with an Oracle database that doesn't support auto incrementation like MySQL does. To achieve the same goal, I had to create a sequence named "my_users_autoi".

My User.rb class looks like this :


class User < ActiveRecord::Base

set_table_name 'my_users'
set_primary_key 'my_pk'
set_sequence_name 'my_users_autoi'

end


As you can see, there is no magic here. You can now manipulate your model, all CRUD operations are available. And if you try to create a new user, you'll notify that the db sequence is used to assign the primary key.

A user can write articles. So there is a one-to-many association between the two entities. The article class respects the two previous conventions but the name of the foreign key is not correct. It should be user_id. We have to configure our model and add the relationship in the User class :


class Article < ActiveRecord::Base

belongs_to :user, :foreign_key => 'by_user'

end

class User < ActiveRecord::Base
...
has_many :articles, :foreign_key => 'by_user'
end


You can then start manipulating your data :

((
usr = User.create(:pseudo => 'antho', :email => 'ahe@me.com')
Article.create(:title => 'My first article', :user => usr, :creation_date => Date.today)
usr.articles.first.title # => 'My first article'
))

And voilaaa!

The Ranking table is however a little more problematic. Users can rate articles, giving them a note between 1 & 5.
The primary key of this table is composite : it is based on BY_USER and FOR_ARTICLE.
ActiveRecord doesn't support composite primary keys but fortunately there is a library supporting this feature.
Install it following the instructions on the website of his author.

When it's done, create the Ranking class and update your previous classes to reflect this new association :


class Ranking < ActiveRecord::Base

set_table_name 'ranking'
set_primary_keys :by_user, :for_article

belongs_to :user
belongs_to :article

end

class User < ActiveRecord::Base

set_table_name 'my_users'
set_primary_key 'my_pk'
set_sequence_name 'my_users_autoi'

has_many :articles, :foreign_key => 'by_user'
has_many :rankings, :foreign_key => 'by_user'

end

class Article < ActiveRecord::Base

set_sequence_name 'articles_autoi'

belongs_to :user, :foreign_key => 'by_user'
has_many :rankings, :foreign_key => 'for_article'

end


Users can now rate your articles :


rk = Ranking.new
rk.rank = 5
rk.by_user = usr.my_pk
rk.for_article = usr.articles.first.id
rk.save


Don't miss the fact that you have to specify explicitly the primary key (user.my_pk & article.id).

And that's it! I think you can now affirm that a Rails application can be easily created on a legacy database!
Bookmark and Share

Add a comment



2 comments for this article



This post rocks ! Thank you !


Written by Ahava on Wed Jun 17 10:01:32 UTC 2009

What about primary keys that are strings?


Written by gerold on Thu Sep 24 11:58:45 UTC 2009