Last day or so I've come up against a couple of intriguing Rails problems while trying to knock up some plugins for an app I'm writing. I'll write up the second of the two problems later, but here goes the first...
Put simply, I wanted to define a route within my plugin. My plugin implemented a controller (and also contained a view for that controller, see one of the latest features to hit edge Rails ahead of Rails 2.0).
I searched to try and see if anyone had come up against a similar task, but didn't see any concrete answers. My testing led me to realise that every time a call to ActionController::Routing::Routes.draw is made, it completely clears and re-generates routes based on the block passed to that method. So simply calling draw with a new block containing my required route wouldn't work; it'd overwrite other routes, or end up getting overwritten by other routes later in the chain.
I then figured it was time to get cracking with some meta-programming, and that I was going to have to re-define and extend the draw method in order to be able to map the routes I want, and do it in a way that'd be flexible and fair to the original Rails routes file, and other plugins that wanted to toy around with routing. I came up with the following:
module ActionController module Routing class RouteSet alias draw_old draw def draw draw_old do |map| map.connect "controller/action", :controller => "mycontroller", :action => "myaction" yield map end end end end end
Let's give this a quick run-through... I'm re-opening the ActionController::Routing module, and specifically the RouteSet class where the draw method exists. I'm using alias to copy the existing draw method to a method name "draw_old", before re-defining the draw method itself. Within my version of the draw method, I'm calling the old one and passing it a block that firstly defines the routes I wanted to add to the application, and that then yields the appropriate mapper object back to any block passed in to the draw method itself. Dependent on where you want your route to appear in the scheme of things, you could always map your plugins custom routes after you yield the mapper to the calling block, so that they appear after any other routes. Another tweak would be to alias the existing draw method to something like "draw_old_APPNAME", where APPNAME is the name of your application. This would ensure that if multiple plugins implemented something similar, that they then wouldn't clash.
There may be a better way to tackle the problem, but after half an hour of working the problem over (mad props to my boy Mike for helping me tweak the solution into something useful and re-usable), I think I came up with a pretty solid answer, and with a bit more time, something that could probably be wrapped up into a module or plugin all of its very own. Bottom line? Ruby as a language rocks, the dynamic nature and meta-programming features opens whole new doors of functional programming to me, and I'm having to really think outside of the box to see some of the amazing things you can do with it.
Comments
Leave a response
Back to recent posts
My name is Elliott Draper, and I'm a developer in the UK, specialising in Ruby and Ruby on Rails.
You can find out more about what I do here, more about me here, or examples of my work here.
Most recent posts
"RailsConf 2009" on May 28 2009
"Freebird" on April 11 2009
"Foot Locker Unlocked" on February 24 2009
Syndication
Articles: (RSS)
Comments: (RSS)
Tags
rufio
el
eldiablo
personal
coding
mono
programming
scrawl
tech
xframework
blogging
web 20
computers
pc
ruby
dotnet
gaming
xbox360
geekiverse
keynote
macworld
blog
rsync
ssh
apple
appletv
iphone
ipod
itunes
macbook
macbookair
amazon
beanstalk
capistrano
ec2
git
heroku
links
merb
rails
rb
rubyonrails
s3
360
fifa
fifa2008
football
pes
pes2008
soccer
xbox
sdk
github
scm
sourcecontrol
britain
budget
democracy
economics
finances
labour
liberals
politics
tories
automobile
car
miscellaneous
tyre
feather
mike
merb manage
gem
rubyforge
activereload
lighthouse
defer_to
router
routing
contributions
coverage
irc
plugins
job
net
work
brightkite
dropbox
evernote
friendfeed
invites
socialthing
twitter
google groups
mailing list
appstore
mac
o2
datamapper
albums
lesser known classics
mcmlxxxv
music
slices
caesars palace
las vegas
wedding
adium
fluid
growl
javascript
meebo
userscripts
blocks
eval
proc
snippet
qotsa
songs for the deaf
advent
advent 4211
laptop
msi
msi wind
netbook
notebook
rumble
edraper
downtime
god
restart
ejdraper
reboot
code coverage
cover up
slice