Sometimes, when you’re building a Rails application, you want to generate different relationships to the same model – or, rather, multiple relationships to multiple perspectives on a model. You can tell ActiveRecord to override the expected class name, but you can also use this technique to create “subsets” of classes for relationships, too. It’s worth remembering that ActiveRecord can generate these for you. By doing the query in the database, rather than filtering afterwards, your application will run faster.

As you can see from that explanation, I’m not exactly the greatest developer, so this is probably best explained with an example from life.

I’m currently working on a CMS – yawn yawn, I know. Anyhow, in this CMS, we have articles, and an Article has_many :comments. Obvious one-to-many relationship, fine. However, comments may or may not be spam, marked by the attribute is_spam. So whilst article.comments will return all the comments on a particular article, it’d be nice to have a class method that returns all the clean comments; article.clean_comments, for instance.

My first stab at this was to add the following method to the Article class:

def clean_comments
  output = []
  self.comments.each do |c|
    output << c unless c.is_spam
  end
  output
end

which is, I suppose, passable idiomatic Ruby, and which does the job; we build an output hash of objects unless the comment is spam. The problem is that if you have, say, an article with a thousand comments - of which 990 are spam, we end up having to generate 1000 objects from the database, and then filter them with Ruby. It'd be faster to select only 10 from the database in the first place, right?

We can do that by defining a new relationship. In our Article model, under has_many :comments, we can add this:

has_many :clean_comments,
         :class_name => 'Comment',
         :conditions => 'is_spam is null',
         :order => 'created_at'

Bingo. That extra has_many allows us to refer to article.clean_comments, and it'll do so directly from the database via SQL. This is a fairly simple example, and I do recommend looking up has_many and has_one (which has similar capabilities) in the Rails API documentation. There always seems to be more depth with Rails than you initially expect, so it's worth digging a little deeper - and you'll make your code leaner, quicker, and better as a result.

Now, I love Ruby on Rails. Really love it. I’m using it for business and for pleasure. And it’s now got me writing boring scripts in Ruby, just to learn the language better. And, you know, it’s a lovely language. So while advocacy and promotion of RoR as a way to develop your webapp is all well and good (because, after all, it’s one framework (albeit a pretty darn good one) amongst many), every now and then the hype bandwagon strikes. Like in this introductory article on Sitepoint, which contains the cracker:

“…without Rails, Ruby is nothing!”

Oh dear.

Rails might have brought Ruby to popularity, but seriously, that sentence is as big a pile of nonsense as any I’ve seen. It’s these kind of sentences, uttered off-hand by Rails-converts still in awe of the hype-bandwagon, that damages the Ruby community – and makes you look like an arse.

Rails and Hypercard

22 December 2005

Gavin mentions the idea that Ruby on Rails might just be the new Hypercard – something I may or may not have discussed with him.

I think he’s right. After one of the London Ruby User Group meets, someone commented that all Rails really needs now is a killer easy-front-end for page layout, or an IDE for apps of some form, and it could really hit the jackpot. I immediately thought of Hypercard; it had the requisite simplicity, grace, and convention, and would be nicely suited to Ruby (just as it was to Applescript).

I’ve mentioned Hypercard before on this site. It was pretty formative in me finding a way I could program computers that wasn’t necessarily reams of code, of first making me aware of UI design, and of making programming fun. Rails has had a similar effect, properly kick-starting me into OO programming, and finally making me understanding and appreciate scripting languages.

The speed of gettings things working, that’s what matters. Not finished – finished might be a long way off – but you’ve always got something to show for your labours. That’s why I like it.

Rails 1.0 (and Locomotive)

14 December 2005

Congratulations to David, and, of course, the rest of the rails-core gang for getting Rails 1.0 out the door. Much promised, long awaited. I’ve been runing 0.13.8 consistently, and decided not to upgrade to the Release Candidates, instead holding out for 1.0.

Well, my Powerbook reinstall went smoothly last weekend, and all that’s left is to install Rails. I was going to follow Dan Benjamin’s excellent instructions, but decided to leave it a few more days for 1.0. That day came early! Unfortunately, life is chocka right now, so there just isn’t time to install it til the weekend. That’s when I gave Locomotive another shot; a self-contained install of Rails, lighttpd with FastCGI, and sqllite. Very impressive, too; just pointed it at a development app, added it to the list, clicked “run” – and there we were in the browser, running on Rails. For the next few days, it’ll let me vent my PHP frustration with minimum hassle. Come the weekend, I’ll install 1.0 proper. Can’t wait to get back on the railsroad…

Agile Webs with Rails

22 November 2005

Quotation of the day, from a colleague walking past my desk:

“I wish we could find a way of developing agile webs. On rails.”

I’d left my copy of the Agile book out.

project.ioni.st on storing sessions in your db. Succinct, handy, and goes straight on the “do not lose!” pile.

PA on Rails

15 November 2005

Penny Arcade redesign and annouce that they’re now running on Rails. Good for them. Knowing how popular PA is, this could be the real test of whether or not “it will scale”…

Brain slowly changing gear

08 November 2005

A short while later, and I’m slowly shifting up, back out of holiday mode. The 280-odd new posts in NetNewsWire are all out of the way. Some interesting stuff – in particular, MacDara’s new look, which is interesting and a little niggling, as it’s a fair bit of the way toward where infovore should be shortly going (though mine will be slightly less chaotically ‘tumbly’) – and also Matt’s recent work for the BBC, which he mentioned at the last Rails/Django meetup. It’s a shame that the London Web Frameworks Day is full – it wasn’t open for registration prior to the holiday, and I’m a bit peeved it’s full. Ah well, there’s still the usual meetup.

My brain’s also beginning to buzz a little, following a whole lot of exciting ideas I had on holiday. Now I’m back, I’ve got the tools to realise them, and also a few more things on the backburner, and it’s all a little bewildering. I’m sure a night’s sleep and a day at work will bring clarity – and a short sharp dose of reality.

Why should it scale?

24 October 2005

The big question around Rails: does it scale?

I say: forget that. Ask this instead: why should it scale?

Rails empowers the lowliest user or homesteader to create applications faster, at a lower cost than ever before. You may have an application that does 75% of what I want to do – but given that Rails puts t even closer to 0 it’s probably be faster for me to start from scratch than it is to try and adapt yours. That way, you have a perfect personalised solution, and so do I. If we looked at our code, they might even resemble each other a little. That’s survival of the fittest, isn’t it?

More and more users will become programmers as the tools, the middleware, the software-to-make-software gets better. Ning is the beginning of this. Users don’t need a generic solution; they’ll all be rolling their own. Software will become more discrete – hell, it’s going to become discerning. The tools we use are very personal; in an ideal world, they’d all scale to a userbase of one.

I guess that we’re all developers now.

A few days I linked to Dema’s tagging mixin for Rails. In, well, about half an hour over the past two days I implemented it into a project I was working on – first into the models, then into visualisation. The interface will come last (though of course, that doesn’t mean it’s not getting a lot of thought right now).

One problem I ran into was that whilst I could tag away with new tags, adding an already-extant tag to a data object didn’t work – it threw an exception error. In the end, I found this was down to my join table – the tags_things table that assigns tags to thing objects. The thing was, as with most of my tables, I stuck an auto-incrementing id column into it. This was really a stupid idea and not in any way necessary (though in all the other tables, it is fairly appropriate). The moment I just left it with two columns, tag_id and thing_id, it all worked fine.

It’s a nice mixin, by the way – makes searching by tag dead easy and it’s fairly lean. Saved me reinventing the wheel, that’s for sure.