KRJS: RJS without messing the Views

Posted by choonkeat Sun, 11 Jun 2006 20:02:00 GMT

RJS is great and awesome. I use it quite regularly now. With RJS, I don't have to deal with which parts of the page to update in the rhtml files - I get to decide whilst in my controller using the nice and elegant render :update. Sweet.

But part of me wished I didn't have to even decide which page elements are to be ajaxified. I'd wish I could more easily enable a link, form or button to make ajax calls without going back and touching my html...

Oh well.

Introducing the KRJS plugin, with less than 60 lines of patch to Rails' ActionPack itself (which probably means bugs are aplenty, would slow production sites to a crawl, and that its fresh from the oven too)

To see KRJS in action (so what does it do?), generate a blank controller and index action:

./script/generate controller Sample index

Give it a decent layout (include javascripts) by creating the file app/views/layouts/sample.rhtml

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"

<%= javascript_include_tag :defaults %>

<%= @content_for_layout %>

Create a sample form:

<%= form_tag({:action => 'submit'}, {:id => 'form'}) %>
<%= text_field 'account', 'login', :id => 'account-new-login' %><br />
<%= submit_tag 'Login' %>
<%= end_form_tag %>

This will be the last time we're touch the Views. If you visit the page now, you should see a simple form. This is the most basic Rails app. It will be our mickey mouse app for this session:

KRJS walkthru: Default form

Clicking on Login leads you to an even simpler error page:

KRJS walkthru: Default page after submitting form

This is because we didn't have any code to handle the form submit. Don't let that stop us web2.0-ers, let's ajaxify it anyways! First, install the KRJS plugin

./script/plugin install

and restart your server.

Now, try to view the page, and click on the Login button.... same error page. Good! That means KRJS didn't mess up the original app. Now let's add a new method into the controller, app/controllers/sample_controller.rb

  def on_form_submit
render :update do |page|
page.insert_html :after, 'form', CGI.escapeHTML(params.inspect)


Refresh the page, and click on Login

KRJS walkthru: Result page after installing KRJS and clicking form

As you can see, the form has become ajaxified - to update the page instead of sending the browser to a new location - by merely adding a new corresponding method in the controller! How about adding this to the controller:


  def on_account_login_blur
render :update do |page|
page.insert_html :after, 'form', CGI.escapeHTML(params.inspect)


Refresh the page, type something into the textfield and TAB away from the field:

KRJS walkthru: Result page after losing focus on text field

Yea, KRJS registers onBlur events as well. In fact, it'll register onClick, onSubmit, onWatever, onYouwant because it doesn't really care. All that matters is your HTML element's ID attribute. KRJS currently identifies xhr actions by naming conventions, hence it will probably be most convenient to be used with dashed_dom_id plugin. 

Go ahead, give it a spin. I'm going to sleep.. hope I don't wake into a world of horror...

[Updated plugin links] 

Posted in software, ruby | Tags krjs, rails, rjs | 2 comments | no trackbacks

i am back
late nights
my demise
iso metric engine
four and a half years
good beginnings
much ado about nothing
another blackout
navigating instead of browsing

(Not) Managing Software Developers

Posted by choonkeat Tue, 30 May 2006 16:06:00 GMT

My monthly dosage of Essential Programmer's Read came in today: (Not) Managing Software Developers. (Life with Joel gone quiet can be pretty bitter... Luckily there's Steve Vegge)

I'm an awful manager myself (lead what? *inside joke*). Not sure if I'll ever venture there again... but I just love these priceless anecdotes:

Go visit most tech companies, and all you'll find is a fussy henhouse parading around an aging goose that laid one or two golden eggs. All their innovation happened in the first act, and now they're focused on "managing for success."

Any time I hear someone say "I want to be a manager", I just want to smack them. But maybe it's just me.

I have indeed interviewed fresh CS graduates who proudly laid out their 5-year plan as "First, I'll have to do some programming... for 1 to 2 years. After that, then I can become a manager." Wow. Priceless. That's a sure hire.

My 2 cents addition to his "Don'ts" list: Don't give frivolous timelines that you know will slip and does slip. The only thing it was good for is to ensure the next one will slip too. And the next next one. And etc, etc. Try to get a personal calendar for reminders instead.

Posted in software | Tags management | no comments | no trackbacks

Bye bye, G-Buy

Posted by choonkeat Mon, 29 May 2006 04:19:00 GMT

If this is true, I'm just so glad Google dropped the name GBuy. For non-locals, here's a hint and some colorful illustrations.

Tags google | 1 comment | no trackbacks

Dirty Little Secret

Posted by choonkeat Thu, 25 May 2006 18:01:00 GMT

I've been doing more Rails development lately (yay!) but have something shameful to admit:

I don't care what variant of many-to-many relationship the models have, I bulldoze with a same implementation everytime.

The nuances and gotchas are too much for my liking. So rather than spending time groking them and risk seeing them deprecated (not complaining, just note things are moving fast), I'd prefer to rely on simpler concepts which are hence more stable and has least-surprise behaviors. Use the time saved to think about real important stuff: business requirements.

Simplifying the concept will mean a tiny bit more code - but lesser wrestling with the framework overall, IMHO. To represent any many-to-many relationship, opt for a rich-association database setup everytime (aka include an auto_increment id in the join table), regardless of whether there'll ultimately be extra attributes. Defer decisions. Hence, == people_skills.person_id and  people_skills.skill_id == in the database will be represented in ActiveRecord as:

  class Person < ActiveRecord::Base
has_and_belongs_to_many :skills
has_many :people_skills, :dependent => :destroy

class Skill < ActiveRecord::Base
has_and_belongs_to_many :people
has_many :people_skills, :dependent => :destroy

class PeopleSkill < ActiveRecord::Base
set_primary_key :not_id # int auto_increment primary key, cannot be named 'id'
belongs_to :person
belongs_to :skill

There 2 lines more than rightfully necessary. But all the data will surely be accessible. If things turns out to be simple, your overhead is negligible. If requirements turns hairy, you're still safe! No worrying over any potential has_many :through quirks, or lack of support with has_and_belongs_to_many. Just go with the above setup - get some code running! - and everything can be optimised later. Wrestling more and things will begin to feel like unnecessary situps to me...

Fixed the sample code above, apparently PeopleSkill's primary key should not be named :id. So its 3 additional lines instead of 2. A tour via ./script/console will be

  >> Person.delete_all
=> 0
>> Skill.delete_all
=> 0
>> PeopleSkill.delete_all
=> 0
>> s = Skill.create :name => "Swimming"
=> #"Swimming", "id"=>1}, @new_record=false, @errors=#>>
>> jack = Person.create :name => "Jack"
=> #"Jack", "id"=>1}, @new_record=false, @errors=#>>
>> jill = Person.create :name => "Jill"
=> #"Jill", "id"=>2}, @new_record=false, @errors=#>>
>> jack.skills << s
=> [#"Swimming", "id"=>1}, @new_record=false, @errors=#>>]
>> jill.skills << s
=> [#"Swimming", "id"=>1}, @new_record=false, @errors=#>>]
>> PeopleSkill.find(:all)
=> [#"1", "skill_id"=>"1", "person_id"=>"1"}>, #"2", "skill_id"=>"1", "person_id"=>"2"}>]
>> jack.skills << Skill.create(:name => "Dancing")
=> [#"Swimming", "id"=>1}, @new_record=false, @errors=#>>, #"Dancing", "id"=>2}, @new_record=false, @errors=#>>]
>> jill.skills << Skill.create(:name => "Cooking")
=> [#"Swimming", "id"=>1}, @new_record=false, @errors=#>>, #"Cooking", "id"=>3}, @new_record=false, @errors=#>>]
>> jack.skills(true)
=> [#"Swimming", "id"=>"1", "not_id"=>"1", "skill_id"=>"1", "person_id"=>"1"}, @readonly=true>, #"Dancing", "id"=>"2", "not_id"=>"3", "skill_id"=>"2", "person_id"=>"1"}, @readonly=true>]
>> jack.destroy
=> #"Jack", "id"=>1}, @skills=[], @new_record=false, @people_skills=[#"1", "skill_id"=>"1", "person_id"=>"1"}>, #"3", "skill_id"=>"2", "person_id"=>"1"}>], @errors=#>>
>> PeopleSkill.find(:all)
=> [#"2", "skill_id"=>"1", "person_id"=>"2"}>, #"4", "skill_id"=>"3", "person_id"=>"2"}>]
>> quit

The reason the original sample code wasn't working was not because of HABTM didn't create the primary key (as mentioned by Josh in the comments), but rather its precisely because it did try to include the id column in the INSERT statement (with a wrong value) thus causing primary key clashes and blah blah blah. Strangely, by changing PeopleSkill's primary key to be named something else, the INSERT statement would exclude it and insert only (`skill_id`, `person_id`), allowing MySQL to auto_generate the primary key.

As long as the primary keys of Person and Skill are not called "id", PeopleSkill can happily use "id" as its auto increment primary key (as is with my original work). My force is not strong enough to attempt a patch / further investigation for this HABTM issue. 

[Update 2]
Plugin available to make habtm behave: Download and unzip into your vendor/plugins folder.

Posted in ruby | Tags associations, rails | 3 comments | no trackbacks

Google Toolbar for RssFwd

Posted by choonkeat Thu, 25 May 2006 11:57:00 GMT

Richard Hensman has just donated a custom button for RssFwd to plug into Google Toolbar. Unfortunately, the Firefox version of the toolbar doesn't support adding a custom button yet - which explains my delay in publishing this. Finally gotten to try it out today and it works pretty sweet :-) Thanks Richard!

If you have Google Toolbar installed, click on the icon below and give RssFwd a spin! 

  Add RssFwd!

Note: it works exactly like the existing bookmarket,

Posted in  | Tags google, toolbar | no comments | no trackbacks

Version Control: That missing module in CS101

Posted by choonkeat Wed, 24 May 2006 14:48:00 GMT

Some of my friends would be groaning "Not again..." but please bear with me while I flush my system clear so as to avoid talking about it again.

What's the big deal with a menial thing like version control? You join any software company and they'll brief you on when to file your transport claims, how to apply leave, use their version control systems and access your voice mail. What's so complex? CVS, Subversion, ClearCase, Visual Source Safe, blah blah blah... just grab any, all the same (get it over with and let's settle the real critical stuff, like install WinXP or Win2k?). You check out, you make changes, you commit, it conflicts, you yell at it, you reboot like how you solved that Outlook crash last Friday and you look for MIS, you try clicking all possible buttons and god-knows-what-happened when finally (finally!), you get your changes into the server - hurray!, then someone screamed like their dog died, "{your name} - what the {expletive} happened to my bug fix!?" and you go, "Wha??? I didn't do anything! This CVS isn't stable - it clobbered your changes! Let's not edit the same files at the same time again!" - and the rest of the day became a CVS101 walk-through cum hands-on session just to show how a CVS commit would not quietly overwrite another person's change on the same file. Branching and merging were words never to be breathed,

Honest to goodness, that really did happen. So much for 5-years experience in developing enterprise Java application. (Ok, that was a cheap shot!)

Version control should simply be taught in schools. Both the concept (good reading!) and practice. If you think its not worth twenty minutes or that you can simply hide your head in the sand and don't ever touch branching and merging - you're not taught enough! I'd even venture to say that version control should be covered with higher priority than SQL - based on the simple fact that all software needs to be in version control (change control, revision control) but not all software will need SQL. e.g. J2ME games, Symbian apps, or an operating system.

Imagine a cooking school churning out chefs who don't wash their hands? What shame! MIS who pulls the plug rather than shutting systems down properly? Yikes! So how can any honorable CS school churn out programmers who'd only know to backup (not even version!) their fabulous online banking website with folders named C:\project\current, C:\project\latest, C:\project\latest2, C:\project\final - Pfft!


I've recently come across, yet again, the opposite school of thought regarding branching in version control. It seems to me that ClearCase users coming to CVS (or alike) would generally get some culture shock. You see, they usually do draconian stuff like file locking and micro branches - create a branch, write code, commit, write more code, commit, then merge back to trunk when complete. Everyone works in their own branch and merge back later.

Over at the CVS camp, people usually work directly off the main trunk (aka HEAD) without file locking. Differences are resolved automagically by the tool and the occasional conflicts are resolved manually. Branches are created only for releases, not your everyday affair.

My friend Harry is still adamant that the ClearCase methodology is more right and doing otherwise is cutting corners. Though I'm not totally convinced, I do see 2 plus points in doing micro branches: You can safely commit anytime (read: broken code) into the repository and scoot off to meet your girlfriend for dinner. When developing on the trunk, committing broken code would've affect other developers. But when not committing, you'd would risk losing unversioned changes in your working folder (Sorry honey, not tonight). However, with modern editors gaining capability to do local versioning, diff and merge (e.g. Eclipse) such risk is getting contained.

The other enterprisy advantage is that by having commits (read: progress) done centrally (unlike an editor's local versioning), its more possible to have a project management systems extract information and build useful overviews and reports on the project's progress - which ClearCase apparently does. The man.

The only question is if its too cumbersome to practice - spending more time with the tool than on the code. And then, there's the distributed crowd.

So perhaps its because schools already made the mistake once before - enough problems trying to cover waterfall, XP, UML methodologies - and curriculum would be simpler with SELECT modules FROM last_year instead.

Posted in software | Tags control, rant, version | no comments | no trackbacks


Posted by choonkeat Sun, 14 May 2006 16:43:00 GMT

I don't suppose many people will need this. But I found myself in a unique situation today, needing to transfer code from one Subversion repository to another. Preferably retaining the history of changesets and comments. Without access to the actual server repository.

So wrote up this little ruby script: svn2svn.rb. 

There's nothing about it that needed it to be written in Ruby. Its just so. In fact I was too lazy to poke at SWIG to get proper Ruby APIs for SVN like Collaboa (aka Trac on Rails). I taken the easy way and used "system" and "popen" instead - blasphemous! The whole algorithm is hardly optimised as well, roughly:

  1. checkout each revision from source repository URL as r1, r2, r3, etc (the CVS equivalent will probably be "each log event")
  2. (create and) checkout the destination repository URL to a working directory
  3. for each revision, patch the diff -Naur output into the working directory and commit (includes svn add and svn remove where needed)

Step #1 will take quite a very long time, depending on connectivity. So, if you ever have the same need, use it at your own risk.

If its any assurance, it worked for me. 

Posted in software | Tags svn | no comments | no trackbacks

Firefox View-Source

Posted by choonkeat Wed, 10 May 2006 15:03:00 GMT

Perhaps the whole-world-but-me already knows this... but I'd really never known I could refresh (Ctrl-R) directly at Firefox's View Source window!

Write some code > View with browser > View source and see generated HTML
Make code changes > Refresh view-source window and see updated HTML

Now that's quite a dandy feature! Only found out just now when I'd accidentally refreshed the "wrong window" (so if you'd already known it, its only because you're clumsier than me. Tsk!)

Tags firefox | 1 comment | no trackbacks

The Code Breakers

Posted by choonkeat Mon, 08 May 2006 06:41:00 GMT

Just got to know there'll be a neat BBC documentary on Free/Open Source Software. Excluding the unearthly 3:30am and 5:30pm showtimes.. the more feasible showtime for Singapore will be: (for other timezones, pls check at BBC directly)

May 11, 2006 - 21:30 - 22:00 - The Code Breakers (r) 1 of 2 - at BBC Channel
For years Microsoft has dominated the world of computing, but its software is beyond the reach of many in the developing nations. This 2-part series investigates that the poorest countries are now changing tack and using Free/Open Source Software (FOSS).
May 18, 2006 - 21:30 - 22:00 - The Code Breakers (r) 1 of 2 - at BBC Channel
For years Microsoft has dominated the world of computing, but its software is beyond the reach of many in the developing nations. This 2-part series investigates that the poorest countries are now changing tack and using Free/Open Source Software (FOSS).

(This hcal output was made using hCalendar creator, neat! Editors should have hcal built in!)

So go home early on 11th, skip an episode of 至尊红颜 or something and go watch this. FOSS isn't just about anti-microsoft.... so hopefully they won't be just talking about Microsoft.

Tags freedom | 2 comments | no trackbacks

Margin at Aljunied was decisive

Posted by choonkeat Mon, 08 May 2006 02:19:00 GMT

Aljunied: 56.1%

I think I've got someone here who needs to take compassionate leave for the results ;-)

Tags  | no comments | no trackbacks

E-mail Digest is so Old School

Posted by choonkeat Tue, 02 May 2006 02:59:00 GMT

Keep up to date through out the day? Have a 1-look overview of all updates? Pick 1. That's what "email digests" means. You get to read only 1 single email containing all the updates - BUT you only get them at the end of the day. That may suit some people, but not me.

So RssFwd has a new feature today. Introducing a clustered view that allow readers to have the best of both worlds! With the help from Gmail of course (and any other e-mail program that has grown up to implement threading intelligently). To enable, just tick the "clustered" option at preview page.

RssFwd messages clustered in Gmail

You get the benefit of keeping up to date wheneva you want to - the individual updates just keeps flowing in as individual emails. Additionally, you get the benefit of a reading everything on a single page when you choose to (end of day, start of day, end of week,... your pick!)

RssFwd messages clustered in Gmail (inside)

RssFwd is attempting to de-throne Google's own, /cackle, and be the defacto RSS reader on Gmail. Hm, then again.. Google Reader was never meant to integrate with Gmail was it?

Posted in  | Tags digest, gmail,  | 9 comments | no trackbacks

God giveth; God taketh away

Posted by choonkeat Fri, 28 Apr 2006 01:40:00 GMT

I can't imagine going back to life without my bestest friend: Now, where do I start finding stuff for my work? Its incredible... and is probably the biggest productivity tool eva.

But today, my bestest friend released SketchUp. A spiffy (only 19mb) cool 3D modelling tool... that integrates with Google Earth. Pfft! There goes my TODO list for the day.

And ya, and the best thing is... SketchUp is script-able with Ruby.

Posted in life | Tags google, Ruby | 2 comments | no trackbacks

RssFwd Blocked In China?

Posted by choonkeat Mon, 03 Apr 2006 05:52:00 GMT

Blogger Wuming_Gong reports that RssFwd is inaccessible from within the Great Firewall of China. Its the equivalence of finding your proprietary software cracked on Astalavista - a good problem indicating your software has arrived.

Posted in  | 4 comments | no trackbacks

Peeking at the Browser's History

Posted by choonkeat Thu, 23 Mar 2006 11:50:00 GMT

Web Developer's Quiz: Your website needs to somehow know what are the other websites a user had already visited. How do you do it? How do you get the information from a browser history?

Kevin Burton pulled it off with a neat trick. When the new features of his Tailrank were released. I must've been sleeping or busy, anyways, didn't check out the improvements in Tailrank till now.

Under "import", a user usually uploads his OPML file (which I'd previously talked about), input some URLs, etc. In his attempt to make Tailrank's import applicable to more layman users, Kevin has a new "Auto Configure" button. Click on it, and a list of popular sites (that you  have visited) are found and is ready for import. Damn, how did it know!

I did some view-source hunting and found document.defaultView.getComputedStyle and element.currentStyle. Explain: Given that your browser will style visited links differently from link not yet visited, Kevin merely printed a bunch of hidden links and used a javascript to pick out those you have visited! Woot! I can sure find some use for that... hmm.. can't think of any now, but I'm sure there're uses!

That said, I would've preferred if Tailrank actually gave me the option to uncheck some of them from my list (especially since removal of feeds isn't implemented yet)

Posted in software | Tags history, javascript, style | no comments | no trackbacks

Re: Additional Thoughts on Why Ruby isn't ready for the Enterprise...

Posted by choonkeat Tue, 21 Mar 2006 02:35:00 GMT

I'm still not going to respond to the complete (longish) article.

First, some agreements,
Ruby is going down a path of creating their own Virtual Machine. It seems to me, that they should simply put Ruby on the Java VM and not waste efforts in reinventing the wheel
VM. Sure. Whatever good stuff that comes. What's for keeps is the Ruby language. Avi Bryant had even contemplated [mp3] that its highly possible having Smalltalk VM (more mature) running Ruby code. Heck, why not?
Ruby needs to address multilingualization quickly
i18n. Definitely. Don't be so sure it ain't coming or nearing. Anyways my 2 cents is, I haven't seen any i18n done right (read: development phase). Runtime support for i18n is mature, and that's the easy part.

Now the negatives,
Ruby seems to be missing something that is otherwise fundamental in other languages which is support for Regular Expressions
Holy cow! Missing regular expressions in Ruby? That's funny. Firstly, its a common complain that Ruby inherited lots of stuff (good and bad) from Perl, guess what's included? My other 2 cents says that Java happens to have the worst regex support. Of cos, I'm talking about syntax.
I also couldn't find the equivalent of instance variables. Wouldn't that make reuse at an enterprise-level somewhat problematic?
Shouldn't the notion of methods being public, private and protected also be a part of every modern language? 
Missing instance variable? Notion of public, private and protected methods? Boy, this guy needs to sit down with Bruce Eckel (Nothing against Bruce, just thought its a funny de ja vu) Or more accurately, sit down with Ryan Davis.

Posted in ruby | 1 comment | no trackbacks

Older posts: 1 2 3 ... 18