Friday, May 29, 2009

Google Wave - Why HTML5?

I have been caught up in the hype of google wave. I'll assume you already know what google wave is (Think of it as a mix of instant messaging with email). After watching the Google I/O presentation video, I was thinking, why does this have to be implemented in html 5? Here are some reasons I can dream up:

  1. Html 5 is a richer markup language, with new elements supporting web apps, not least of which is native support for video and other media. It has better support for web apps, including the well known canvas.
  2. Html5 is still in development, so the developers of wave can suggest new features that would be useful for their application. At about 16minutes into the video they mention that they are working on a proposal to get a feature added into html5. The wave team had one feature that they want html 5 to support, which is dragging and dropping files from the local machine into the browser. Currently they use google gears to provide this functionality.
  3. The local storage feature of html5 enables the use of more data in a single web app. So even though there can be a lot of information in each wave, the wave can be brought up instantaneously, and the user can scroll through the history of the messages for a single wave, and the app is still highly responsive. (I am assuming this was done using local storage, otherwise I can't imagine xml and media over the network would be as fast as I saw.
  4. The next version of Internet Explorer (8) does not have full support for html5. Even though the google guys say they are happy that Microsoft will support html5 in the future, this will not happen immediately, and IE will lose market share if google wave really takes off.
  5. This is the main one for me. Google believes that html5 is the future of the web. Google doesn't have to create their own OS, because html5 is going to be the next operating system of the web. With html5 there is no need for flash, no need for silverlight, or a particular browser. Google can continue doing what they do best, which (after search and advertising) is build web apps using raw html and javascript.

Some of these reasons are more side-effects than causes. Either way, with google wave, html 5 has become a much more important language for web developers, and for me Wave has brought html5 very much from a working draft, into the near future.

Thursday, May 21, 2009

ActiveRecord Oracle Enhanced adapter with legacy tables - primary key triggers.

I was using active record, Inserting data into tables that have triggers set up to create the primary key from a sequence of numbers. The oracle adapter doesn't support this 'out of the box'.

When I read about the approach that the oracle adapter takes to auto incrementing primary keys, my first thought was that it was a bad idea. Why wouldn't you use the 'standard' approach of creating a sequence for the primary key, and writing a trigger to set the primary to the next value of the sequence upon creation of a record? This ensures that the same policy is used, whether a stored procedure or an ad-hoc insert is used. (I am talking about the fact that the oracle adapter creates its own primary key using #next_sequence_value in oracle_enhanced_adapter.rb.)

It's probably just me; I am coming from the viewpoint of someone who has spent the last 3 years working with oracle databases using plsql stored procedures to program much of the logic. I already have the sequences (which ActiveRecord migrations create automatically). I also have triggers, which interfere with the adapters behaviour.

To someone who just wants to move their rails application onto an oracle database, the approach taken by the adapter makes more sense. Also no oracle-specific code (outside of the adapter itself) has to be used.

I can imagine an adapter for data definition commands (eg table creation), encapsulating this code, but as far as I know, rails migrations are fairly basic when it comes to setting up a database. They require extra setup for foreign keys, for example.

I tried searching for a solution in the blogosphere, this post mentions this problem, but is actually about an issue with LOBs, which is solved in a later version.

Raimonds Simanovskis, the maintainer of the adapter, blogged about custom activerecord methods for legacy oracle databases.
It didn't help, because my knowledge of how activerecord adapters work was pretty limited at the time. (It is only slightly less limited now).

I posted to the "oracle-enhanced" google group and Raimonds was kind enough to improvise an 'ugly' solution. I tried it out and it seemed to work.

I added the code to the end of the apps config/environment.rb:
class ActiveRecord::Base
set_create_method do    
quoted_attributes = attributes_with_quotes
conn = connection.raw_connection
cursor = conn.parse <<-EOS
BEGIN
INSERT INTO #{self.class.quoted_table_name} (#{quoted_column_names.join(', ')}) 
VALUES(#{quoted_attributes.values.join(', ')})
RETURNING #{self.class.primary_key} INTO :id;
END;
EOS
cursor.bind_param(':id', nil, Integer)
cursor.exec
id = cursor[':id']
cursor.close
id
end
end

What does this code do? It replaces the default active record create method with a method that sends a small pl/sql
script (the bit between BEGIN and END) which gets the new primary key. Note this works even if you change the name of
the primary key in your model using set_primary_key.

This also requires the plsql gem to be installed, which seems to be required for the adapter anyway.

There is one major shortcoming; this patch causes inserts to only work with tables that have an auto-increment sequence and trigger combination set up.

Ideally, this code could be incorporated into the adapter, and a setting could be used to switch it on or off. I don't know if there would be much demand for it, though.