Creating route urls dynamically in Rails5

17-Jan-2019 • 3 min read

If you are aware of the rails ecosystem, resource routes are generated in rails usually with ids of the corresponding resources in your relational database. For instance your url might look like below.

https://www.website.com/articles/3

The above url notation seems okay for us as developers, but it is not intuitive to viewers of your page. It will be more intuitive if there is a url something like

https://www.website.com/this-is-article-3

Interestingly rails has a way to accommodate above url notation. You just need something like below in your routes.rb file.

get '/this-is-article-3' => 'article#show', defaults: { id: article_id }

instead of

get '/articles/:id' => 'article#show'

This kind of routes are called named routes. Looks good so far. But how can you define a routes for every article resource you are going to put in your application? One way is to define routes for every article as specified above in your routes.rb file. But this is cumbersome and error prone.

What you can do is something like below in your routes.rb file.

config/routes.rb

  Article.all.each do |article|
    front_matter = JSON.parse(article.front_matter, object_class: OpenStruct)
    url_text = front_matter.title.parameterize
    get "/#{url_text}" => 'articles#show', defaults: { id: article.id }
  end

The above code loops over all the article resources and extracts url information and creates a dynamic route for each. One more thing to do is to reload the routes whenever any new insert happens in article resource. For that let's add a 'after_save' hook for article resource in corresponding model.

app/models/article.rb

  after_save :reload_routes

  def reload_routes
    Rails.application.reload_routes!
  end