Building dynamic routes in Ruby on Rails site

This is something I’ve built a couple of times over the years, particularly in building custom CMS’s. I don’t remember seeing it  written up anywhere, but I’ve used it since the Rails 1.x days.

The use case being when the users can create pages on the backend with unique name and someurl slug n (A slug is the part of a URL which identifies a page using human readable words preferably based on the name), and you want your app to respond to a dynamic request, like :

http://yourdomain.com/someurl

rather than the not as flat url :

http://yourdomain.com/page/someurl

So the general way to handle this is to, at the end of your route.rb file to have a general controller (let us call it a dyno-path controller) as a last router action.

The reason to make it the last route in the route file is so all the known paths are handled first (you are not re inventing the route file in your custom controller).

So, after the root route and your known hardcode routes/controllers, you pass the path param to your dyno-path router controller which is then going to look up passed param in the “slug” column of the database and figure out which view to build (or which other controller to pass it on to)

This is really just a more general case of the /user/:id example of routing to the index method of the user controller with the id param having the value of :id, but by making it last you have already (efficiently) handled the know and hardcoded url paths and or now dealing with the /:path to dyno-path controller. 

You will also have to handle the case when you can’t find the passed path and redirect to some kind of 404 “can’t find that page”.

Also when you are creating the slug values that you (or your users) are creating make sure to exclude the hardcoded paths you have in your router.rb file or someone going to be unpleasantly surprised.  It should be possible to do so programmability via ActionController::Routing, but maintaining a list of reserved path keywords would be fine too if you document your routes.rb so that this needs keeping up to date.

using the route match syntax it would look like :

1
match '/:url' ,to 'dyno-path#show', via: :get

in Rails 2.x it would look like

1
 map.connect ':url', :controller => 'dyno-path', :action => 'show'

This is all kind of obvious in retrospect but then isn’t it always. In retrospect.

Update: with a bit of googling I found this recent post Creating Dynamic Routes at runtime in Rails which takes a much fancier approach; and this older (2009) stackoverflow Ruby on rails route to a custom method in the controller from the view which covers the same ground.

Leave a Reply