2008-09-08

D.R.Y Class Methods in Rails

There you are, coding something fairly simple. In my case I wanted the latest ActiveRecord object, either created or modified. I had this in my model;
def self.find_last_updated
find(:first, :order => "updated_at DESC")
end

I wanted to reuse this code in other models. The natural progression is to stick it in a file into the /lib/ directory. However, there's a slight gotcha. You can't have class methods in modules without a bit of trickery.
The way I went ahead was that I created a file in /lib/, in my case, I had generic_helper.rb in there, so I decided this was such common code that I can put it in there. Then load it with include GenericHelper. But that didn't work.
Thanks to Marcus, I now know how to fix this. What you do is you create another module within your module, and ditch the self. part from the method declaration. Something like this:
module GenericHelper
module ClassMethods
def find_last_updated
find(:first, :order => "updated_at DESC")
end
end
end

You can then load the code with this:
include GenericHelper
extend GenericHelper::ClassMethods

Now, that's pretty neat, and it allows you to choose if you want to load the class methods or not. However, if you stick it in a file on its own, then you don't need to choose that, and here's a piece of code that allows you to omit the extend-part.
def self.included(cls)
cls.extend ClassMethods # The nested Module's name
end

What this does is it basically pushes itself through the door and extends itself. You should now end up with something like this:
module GenericHelper
def self.included(cls)
cls.extend ClassMethods # The nested Module's name
end

module ClassMethods
def find_last_updated
find(:first, :order => "updated_at DESC")
end
end
end

In /lib/generic_helper.rb. Which you can "activate" by using the include statement such as: include GenericHelper. I can now go into the console and ask for MyActiveRecordModel.find_last_updated. Pretty neat, huh?! Ruby for President!
Now, how could the almighty Marcus know all this..?! Well, he's go a secret (no, not that one). He's been watching Dave Thomas' Screencasts from the "The Ruby Object Model and Metaprogramming"-series. Needless to say those are on my shopping list.

3 comments:

the boy said...

ruby is ugly like those chicks on a saturday night which make you think "eek i'd need like, 10 pints and a paper bag to hit that" but then you hit it anyway and wake up in the morning all like, "OH NOES!! how will anyone ever take me seriously again..."

so in conclusion, you actually had more credibility as a php monkey...you need to drop that shit and write this whole period off on your CV as a long stint in rehab or something :-P

andrew said...

@the boy:
don't you talk about his chick like that. I've had her, and she's real fine.
php...? they get to version 6 they get all saggy and bloated. not a pilf.

J said...

Hey Boy, you're a Microsoft Biyatch, therefore your opinion wouldn't even be counted in a discussion about whether Sam Fox has got large knockers or not.
Now shut it and go code some VB or C-Hash!