Yet Another Rails Newbie

June 5, 2006

Migrate the way.

Filed under: ActiveRecord, RubyOnRails — Richard @ 10:13 pm

Yesterday I spent a couple of hours fathoming out how to use migration. I've read several articles and blogs saying that this is the best way to create your database tables in Rails, so thought I'd give it a go.

Firstly, the fact that it's possible to update your database schema, or rollback to a previous version seemed great. You simply type ruby script/generate migration SomeDescription and you have a file created in the db/migrate folder called something like 001_some_description.rb.

Then, next time you want to modify the database you type ruby script/generate migration AnotherDescription and another file called 002_another_description.rb would appear. So far so good.

But what happens if there's a problem in your migration code. For example, I accidentally had a field of type :booolean (with the extra 'o'). Then, when I ran rake migrate, there was a MySQL error and the migration stopped. Some of the migration had succeeded and one of the tables had been created, but the schema_info table which tracks which version is actually in the database still contained the previous version number. It seemed odd that if a migration fails, then it doesn't automatically call the self.down method to restore the database to the working version. Instead, I manually had to go into the MySQL command line, type UPDATE schema_info SET version = 2 (which was the version that failed) and then I could use rake migrate VERSION=1 to undo the partly updated tables. I was then able to correct my typo and re-rake the migration. Also noting that VERSION has to be in upper case which caught me out the first time I tried. I guess I could have manually undone the changes that Rails had made, but since I'd already defined these for the rollback, it seemed easier to use rake.

Another thing which I wasn't sure about was foreign keys. I'm a full time web developer and at work, whenever there are relationships, there are foreign keys. I was surprised to find that Rails doesn't have them! I knew about has_many and belongs_to – but these, to my surprise didn't enforce any data integrity. So I could have any value in one table that didn't exist in the id column of another. I wasn't happy about this. There had to be some way to stop this from happening. After many searches on Google, I found that it's possible to add validation to the model before data is inserted into the database:

class Site < ActiveRecord::Base
   belongs_to :category

   def validate
      errors.add_to_base "Error description" unless Category.exists?(category_id)
   end
end

Which did just what I wanted. Every row that was inserted into the sites table, would check that the category Id existed in categories and fail if it wasn't valid.

However, there's an even better way (as I see it at the moment). RedHill Consulting have created a Rails plugin (http://www.redhillconsulting.com.au/rails_plugins.html) which adds a foreign key to the database when you rake. All you have to do it run these two commands after making sure that SVN is installed on your computer (OSX users go here: http://www.codingmonkeys.de/mbo/):

script/plugin install svn://rubyforge.org//var/svn/redhillonrails/trunk/vendor/plugins/schema_defining

script/plugin install svn://rubyforge.org//var/svn/redhillonrails/trunk/vendor/plugins/foreign_key_migrations

Then, each time you migrate, the foreign keys are added to the database. I've only tried this using MySQL for now but from what I think I read, it should work for others too.

Discuss.

No Comments Yet »

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a comment

Blog at WordPress.com.