Search code examples
ruby-on-railsrubynested-routesancestry

rails - how to make nested route with ancestry


I have a single model:

class Page < ActiveRecord::Base
    has_ancestry
    validates :slug, :name, uniqueness: true, presence: true
    before_validation :generate_slug

    def to_param
        slug
    end

    def generate_slug
        self.slug = Russian.translit(name).parameterize
    end
end

and I'm using ancestry gem to create tree of pages and subpages, i.e. page can have multiple sub-pages and sub-pages can also have multiple sub-pages, and so on to infinity.

But my problem is that I can't make something is /page-1/page-1-2/page-1-2-1. All sub-pages have a URL is: /page-1-2 or /page-1-3-1.

My routes.rb:

Rails.application.routes.draw do
    get '/pages' => 'pages#index'

    resources :pages, path: "", path_names: { new: 'add' }

    root 'pages#index'
end

How to make nested URL?

Thanks!


Solution

  • As far as I know there's no neat way of capturing nested tree structured routes with dynamic permalinks, you can create a named route to capture pretty nested pages path:

    get '/p/*id', :to => 'pages#show', :as => :nested_pages
    

    Also, make sure you update slug of your page object to have nested urls, i.e.: append parent pages' slug to it. For example:

    page1.slug = '/page-1'
    page2.slug = '/page-1/page-2' # page2 is a child of page1
    page3.slug = '/page-1/page-2/page-3' # page3 is a child of page2
    

    So, to make this work, you can probably change generate_slug method in your Page model class:

    def generate_slug
      name_as_slug = Russian.translit(name).parameterize
      if parent.present?
        self.slug = [parent.slug, (slug.blank? ? name_as_slug : slug.split('/').last)].join('/')
      else
        self.slug = name_as_slug if slug.blank?
      end
    end