[Post summary: new release with support for ActiveRecord Associations]
This project started with an innocent idea as I walked along the street: you could easily write a find method for composite keys. “What’s the big deal about composite keys?”
I sat down and wrote the find method. But the crud operations didn’t work: create, update, destroy. So I rewrote them for composite key records. I released a gem on various mailing lists to see if the solution worked for other people. People were able to drop it into their legacy system and get it working instantly, and they were thrilled. Cool.
Support for CRUD is only half the job of adding Composite Primary Key support to ActiveRecords/Rails. The other half of ActiveRecord magic is its wonderful support for Associations: has_many, has_one, and belongs_to.
I wrote the association unit tests first and kept extending ActiveRecords until all the tests worked. [A much quicker edit-n-test method than using the console/irb].
And today I uploaded the latest release of Composite Primary Keys with support for Associations. Install it with gem install composite_primary_keys and include require 'composite_primary_keys' in your environment.rb (for Rails apps) or within your Ruby scripts. Visit http://compositekeys.rubyforge.org for other information.
Let me know if it works for you!
At Railsconf, there were several sessions dedicated to 5 minute “lightning talks”. Most 5 minute units of time were used by presenters to show off their product/service. I took 5 minutes of everyone’s time to do the opposite.
When everyone comes to Rails for the first time – http://www.rubyonrails.org – they see DHH’s videos where he uses his Mac and a cool IDE to do wonderful things with Rails. The new person probably doesn’t distinguish immediately what part of the demo was Ruby, what was Rails, what was the cool IDE, and what was the Mac. But it looks cool. The IDE in question is called TextMate. The consequences of this technical demo quadrella were obvious at Railsconf, 90% of laptops were Macs. I’m sure 100% of IDEs used on the Macs were TextMate.
I’m in the 10% of laptops. TextMate isn’t available for my machine, and I’d never see TextMate up close. Doing its thing LIVE. So I had someone show me. For my own amusement, I followed along with my RadRails IDE, seeing if I could do what he did.
He used shortcut key combos to autogenerate text – “snippets” in TextMate. I found I could do the same in RadRails (Ctrl-Space activates the “templates” feature within Ruby and RHTML views).
He had a snazzy black background with multi-coloured fonts. My friend Brett had built a theme for RadRails to look the same as TextMate.
I forget the rest of the demo. I was too busy stroking my copy of RadRails like a pet puppy, and thinking “RadRails is free. TextMate is $46. That seems odd.”
So when I stood up at the Lightning talks, I used 5 minutes of 150 peoples time, to tell 90% of them that they wasted $46, and to inform the other 10% (hmm… 15 ppl) that they could use RadRails. I did a demo. It was fun.
If you have access to the videos that have been made of Railsconf – and I strongly recommend spending the $100 to get access to them if you didn’t go – you can see me revving up the crowd.
Day 3. Lightning Talks. 2nd last speaker.
Great conference. Buy the videos.
First, what is an ActiveRecord primary key currently? There are two versions of a primary key: an integer (12) and a string (’12′). That is, Person.find(1) and Person.find(’1′) return the same thing.
This is the theme of the composite key solution – any conceivable notion of 2+ numbers should work as well as any other. So, [12,2] should work, as should ’12,2′, as should ['12','2']. That is, Membership.find(12,2), Membership.find(’12,2′), Membership.find([12, 2]), Membership.find(’12′,’2′), etc, are treated the same.
Normally, if you want to find multiple objects by their primary key, you pass a list, so Person.find(1,2,3) and Person.find(’1′,’2′,’3′) give the same result.
For composite keys, there are many variations that you can use interchangably: Membership.find([12,1],[12,2],[12,3]) is the same as Membership.find(’12,1′,’12,2′,’12,3′) is the same as Membership.find(’12,1;12,2;12,3′).
The id of a normal object is the value of its primary key field. So Person.find(1).id == 1, and Person.find(’1′).id == 1.
To support interchangable use of the id value within your applications, the composite key result is a CompositeIds object, a subclass of Array where to_s method joins the keys by a comma. Want to pass the id of a composite object to your HTML and back to the server in URLs? You won’t need to do anything differently than you do now. The to_param method will return a string joined by commas – e.g. ’12,1′ – which will be happily accepted by your find method when you receive the value in your controller action methods.
The main code change that you will need to consider is that the primary_key method returns a list of column names, instead of a single column name. (Actually it returns a CompositeKeys instance which subclasses Array, and its to_s method joins the values by a comma).
If you find that Composite Primary Keys isn’t working in a sexily smooth way, let me know so the interface can be improved.