Friday, June 30, 2006

[Rails] How to work with non-autogenerated primary keys

Oddly enough, I have not found a clear explanation of how to make ActiveRecord work with a table that has a non-autogenerated primary key. In other words, the table has a column as a primary key for which the value has to be inserted manually. (Of course this is not good practice but what other better reason to do this than to say such a table already exists and needed a user interface for maintaining its values!)
So how do we go about doing this? Simple. First, set the primary key in the Model object to be the column in the table (since ActiveRecord always assumes primary key is a column called "id"). If we just run this and try to save the model object by firing up the rails console, rails gives an error saying there are no attributes "col1". This is because, rails assumes that the primary key is not editable. So all we have to do is define attributes for the primary key column col1. The overall changes are shown below:

class MyModel < ActiveRecord::Base
set_primary_key "col1"
def col1
read_attribute "col1"
end
def col1=(value)
write_attribute "col1", value
end
end

Now fire up the rails console and create and save the model object, setting values for the required columns. Voila!

Note: since you are departing a bit from rails convention of primary keys, you will need to make sure that the required validations are added in the model so that you dont get errors from the database.

Wednesday, May 31, 2006

Data comparison? Python file comparison to the rescue!

I had to update some data in a production database for a new functionality. I had already done that in the test database during development, but it was not just a simple insert. The steps that I did went something like this:

1. Generate a file with a set of insert statements (used Python for this!).
2. Manually change some data in the insert statements.
3. Run the insert statements

Now since I had to do the same in production, I wanted to make sure that after this insert, the data would look exactly the same as it did now in test. In other words, I wanted to be able to repeatedly run the process above, and make sure that the steps produced always the same set of data. This would guard against any mistakes being done during step 2, which is a manual edit of a file and prone to error.
Sounds simple - I could generate the file of insert statements, and then compare it against the file that was already changed and used to load the data in the table. Problem is, I no longer had that file I could compare against. So instead of comparing insert statements, I would have to compare data. The process I did went something like this:

1. Export current data in the table to a file, say file1.txt
2. Delete the inserted rows from the table.
3. Generate insert statements again, manually edit, and insert rows into the table.
4. Export data in the table to a file, say file2.txt

Now all I had to do, was compare file1.txt and file2.txt. If they are equivalent, it means my manual edits were on target.

So how did I compare the two files? Python to the rescue! This is all it took:

import filecmp
filecmp.cmp('file1.txt', 'file2.txt')

If they are equal it returns true, else false.

I have to admit that that the only reason I thought about comparing data rather than the insert statements was because I was sure Python would have something neat for file comparison. The database-oriented guys might have fired up some magic by using stored procedures and temporary tables, and it would have been equally satisfying to them.

Its all a matter of what you are comfortable with, I guess.

Tuesday, May 30, 2006

Churning out Rails dishes - I

What I learnt from Rails Recipes today:

You can run tests in rails without connecting to the database
test_help.rb is reponsible for the database connection code, so remove reference of test_help.rb from test_helper.rb put in the code yourself. Remove the lines that access Activerecord.

You can connect to multiple databases
All model classes inherit ActiveRecord::Base's connection. So create a parent model class that inherits from ActiveRecord::Base and override the establish_connection method to access the other database. All models inherited from this model class will connect to the new database. Make sure not to instantiate the parent model class since theres no corresponding table.

Integrate with legacy databases
Use attributes and methods like ActiveRecord::Base.table_name_prefix, ActiveRecord::Base.primary_key_prefix_type = :table_name_with_underscore, ActiveRecord::Base.set_primary_key, ActiveRecord::Base.pluralize_table_names to tailor your model class according to the table specifications.

Avoid code repetition(use DRY) in your database configuration YAML files
You can define a section and give it a key. Using that key in various places in your yaml file will substitute the values from that section in those places.

Friday, May 26, 2006

Preparing for RailsConf

When you go to a conference, its always a better experience if you are somewhat knowledgeable about the topics. :) Otherwise the only benefit would be the t-shirts and coffee mugs! And even though the price of RailsConf is a steal judging by the speakers and the topic itself, its quite a bit for just conference paraphernalia!
So starting today(yesterday actually), I am going to be reading up on Rails Recipes, a wonderful book by ChadFowler et al, that details tips and tricks that you an do with Rails. The plan is to read or work through 3 or 4 rails recipes a day. Hopefully this will get me into "Rails mode" and I will be able to avoid a blank, stunned stare when the magicians whip up their rails magic!

Onward to Railsconf 2006

This is the first conference I am attending in quite a while. Last one was XML Devcon 2000! It was good, but not as enriching as I hoped it would be. I suspect that maybe because of 2 factors: one, the general concept of XML was not very appealing to me, ie, while developing, consuming or writing out xml, it does not give me a rush. Second, my understanding of software concepts was clouded too much by what was happening in the world, without me having my own perspective. As folks dished out their own takes and the "one right way" to do stuff, I lapped it all up, not thinking much for myself.
Six years later, I dont how much has changed on my side, but I do like where I am now. I do have perspectives on what "superior" languages or frameworks are, and I do feel a certain rush when I understand or implement concepts. At the same time, having these perspectives has also oddly left me with more tolerance for accepting other concepts or approaches that were previously frowned upon by the "best practice" advocates. So with this bent of mind, I am eager to see how my experience will be at the conference.
Besides the fact that the conference is about a subject that I love developing with, it also boasts speakers that I have always wanted to hear - like Martin Fowler and Paul Graham. In the beginning of the year, while announcing the keynote speakers for the conference, Chad Fowler said "If you can only make it to one conference this year, let RailsConf be the one".

I am happy I listened.