Well, this has been a pain. I have a case where I need to have the ID of a resource be a string, not an integer. Rails routes don’t like that — if you search a bit, you’ll find a number of arguments about the practice, with the Rails core folks coming down on the side of integer-only IDs. Shame that, and people have come up with various workarounds. For me, I ended up doing this:
map.resources :workers map.inventor 'worker/:id', :controller => 'workers', :action => 'show' # In the view, I can then do this, which isn't pretty but is temporary, okay? link_to worker_name, worker_path("#{CGI::escape(worker_name)}")
I have my nice RESTful routes created for workers, which is nice for the usual index, update, destroy, etc which I can do using IDs most of the time. But for show, I need to be able to pass in a name rather than an integer. That’s where the unfortunate additional named route comes in, so I can have a URL like /worker/your_name_here
. It’s human-readable and SEO-friendly, plus for various reasons I’m working with String keys instead of integers in this case (using Redis as the data store).
So that worked…except that I discovered some cases where the strings contained periods. Which is another Rails no-no! Sigh. So, I could muck around with additional special cases in my routes file, which is not nice. Thankfully, though, my searching stumbled on a couple of bugs filed in the Rails core, most particularly this one, which provided a workaround that’s not too awful. I changed my route to the following:
map.inventor 'worker/:id', :requirements => { :id => /.*/ }, :controller => 'workers', :action => 'show'
Et voila, there we go. Adding the requirements
parameter instructs Rails to allow periods, and it works. But I still hate routes.