Thursday, September 23, 2010

Easy Way Out of The STI Hell

I like the idea of STI (single table inheritance), it is cheap, dodgy but it works and allows you to play with all sorts of sub-types in a civilized way. For example you can redefine things in subclasses, use strategies and so one.

But when you try STI with Rails, you immediately fall into the polymorphic routes hell. Because you have new types, Rails tries to find routes for them, and it doesn't want to use the base model as a fallback. And here, people start to do all kinds of things (I did), define controller level helpers, generators, modules and so one. But then, someone adds a new custom method or a new subtype and it all falls down like a house of cards.

Well, you know what they say, the exit from a hell lays at the very bottom of it. And in Rails it will be routes. Say I want to handle all sorts of User model subclasses, like User::Admin, User::Manager, User::Blocked.

Trololo::Application.routes.draw do
# here I collect all the User subtypes
user_types = Dir["#{Rails.root}/app/models/user/*.rb"].map do |name|
"user_" + File.basename(name).gsub('.rb', '').pluralize

# and then I put all of them one by one
(['users'] + user_types).each do |name|
resources name, :controller => 'users', :path => '/users' do
member do
get 'stats'

resources :comments # we can define nested resources too

I use the Rails 3 notation in this case, but I suppose you can figure how to make it work under Rails 2 as well.

It is still a bit dodgy, but it is better and more stable than defining those type-specific routes manually in controllers, you also can automatically handle all the nested routes as well.

That's it, hope that will help

Thursday, September 9, 2010

RightJS 2 jQuerysh Plugin

Hey folks. I had couple of minutes of free time and cooked a fancy plugin for RightJS 2.

It's called 'jQuerysh' and provides the jquery-like behavior for the $() function. You can copypast or build it from over here jquerysh on github

Basically it does three things with the $() function. You can navigate in jquery-style

$('#element-id').onClick('addClass', 'marked');

$('div.class').each('addClass', 'marked');

And you can call the onReady via it, same way as in jQuery

$(function() {
// will be executed when on ready

This is pretty much it, might be useful for people who need to work with both jQuery and RightJS.

And yes, it works with RightJS 2 only. Not like I want to make you switch to RJS2 (which I actually want), RJS1 is simply not built for that.


RightJS 1 Chrome Issues

As much as I like to think about webkit as the world's savior, it constantly produces all sorts of weird stuff in Google Chrome, the last update of which had killed some important feature in RightJS 1 (do those folks even think before they make such changes? because I guess it won't be a problem of RightJS only)

In any case, the shorts and longs of the story is that they screwed the Element#hidden() method, which broke down several UI units, Autocompleter, Calendar, Lightbox, Selectable and Tooltips.

I've published a package for you over here RightJS 1 UI Fixes. It has patched builds of all those widgets, plus a fresh RightJS 1 build with backports from RightJS 2.

If this core-build will cause you troubles, you can patch your own by a simple line of code like that

visible: function() {
return this.getStyle('display') !== 'none';

And don't use the Element#hidden() method in your code, use Element#visible() instead.

Also think about moving to RightJS2, it works with wrappers and therefore doesn't have such issues by design.