First Attempts With Rails: All Failures

Saturday, January 14, 2006, at 07:12AM

By Eric Richardson

Though I'm definitely a dyed-through Perl guy, I've been messing around with learning some Ruby on Rails over the past week or two. The Rails framework has some ideas to it that I think are really nice, so I think it's more a practical exercise than an attempt to stay buzzword-compliant.

I keep running into problems, though, and I think they largely stem from my refusal to start with crappy little address book style learning apps. I want to do something real, and it just so happens that my real life apps, though not especially complex, each have one or two little things in them that throw me off the Rails beginner curve.

Generic Table Structures

For instance, in my first attempt I wanted to port a little application that pulls condo records out of a db and formats them into HTML. Right now I've got a little mod_perl handler doing that, using the template language I wrote for eThreads.

The data model for the app assumes that I know a couple fields that I'll always have, but that there are 30+ more fields that I don't care enough about to actually create hardwired table fields for. So my two tables look as follows:

CREATE TABLE `condo_h` (
  `id` int(11) NOT NULL auto_increment,
  `name` varchar(80) NOT NULL default '',
  `address` varchar(80) default NULL,
  `coords` point default NULL,
  `image` varchar(80) default NULL,
  PRIMARY KEY  (`id`)
);

CREATE TABLE `condo_d` (
  `id` int(11) NOT NULL default '0',
  `ident` varchar(40) NOT NULL default '',
  `value` text,
  PRIMARY KEY  (`id`,`ident`)
);

It's a pretty straight-forward :has_many, :belongs_to relationship, and one that I would represent in two SQL statements: one to get the header and one to get the data. In my mod_perl app I then just build a hash combining the two bits of data and I'm good to go. Sure, for any specific set of fields it's going to be a bit less efficient, but I'm a big fan of the convenience in situations where you can get away with it.

In rails, though, I hit a dead end trying to figure out how to load both sets of data into one instance, so that I could call @condo.id and @condo.data.num_units and get what I wanted.

Special Handling for Table Fields

Also in the above is another issue I didn't mention, but which also hit me in my second attempted app. A site I'm working on deals with geotagged data, and one big thing I need to do is be able to find points that fall inside a given box. In my mod_perl implementation I had used MySQL's GIS support to make a 'loc' field that was defined as a point. That allows me to do fun things like:

select 
    id,x(loc),y(loc)
from 
    markers
where 
    status = 1
    and MBRContains(
        GeomFromText('LineString(
            $self->{minX} $self->{minY},
            $self->{maxX} $self->{maxY}
        )'),
        loc
    )

That may look complicated, but it feels nicer to me than doing the greater than / less than game:

select 
    id,lon,lat
from 
    markers 
where 
    status = 1 
    and (
        lon > $self->{minX}
        and lon < $self->{maxX}
        and lat > $self->{minY}
        and lat < $self->{maxY}
    )

In rails, though, I couldn't figure out how to custom-define the fields I wanted to retrieve (so that I could get x(loc) and y(loc) instead of loc) without throwing out most of the benefit of ActiveRecord. Sure, there's probably a way in there somewhere but various experiments always left me falling back to find_by_sql and trying to figure out how to overload data getting written back into the table (via things like write_attribute).

Again, I think all this really shows is that I suck at being the guy to code easy examples. It also shows that in Rails you really need to look beyond the scaffolding and figure out how all the pieces are working before you can use it for anything out of the straight-forward Rails way of thinking.