Reputation: 28853
In my Rails app I have pages which are stored in the database.
So for example:
id: 1
name: 'About'
slug: 'about'
parent_id: null
id: 2
name: 'Team'
slug: 'team'
parent_id: 1
id: 3
name: 'Cameron'
slug: 'cameron'
parent_id: 2
The slug is used to access them via the routing like so:
match '/:slug' => 'pages#show', :via => :get, :as => :page
So I could access those pages at:
/about
/team
/cameron
What I want to do is use the parent_id
so that the routing becomes:
/about/team/cameron
Can this be achieved using routing alone? Or do I need to do something else as well?
Upvotes: 4
Views: 380
Reputation: 523
Take a help at Friendly gem, it simplifies routing with slugs a lot.
Alternative options to define routes like
As far as I know there's no good way to routes with dynamic paramlinks, 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 = '/about'
page2.slug = '/about/team' # team is a child of about
page3.slug = '/about/team/cameron' # cameron is a child of team
so that you can be made it like this
get '/p/*id', :to => 'pages#show', :via => :get, :as => :nested_pages or pages
So, to make this work, you can probably change generate_slug method in your Page model class:
def generate_slug
name_as_slug = 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
Upvotes: 0
Reputation: 8518
You can't achieve this with nested routes, but you can with route globbing and wildcards. Let me outline the steps it probably takes to realize it, for you:
get '*path', to: 'pages#show'
to the end of your routes file, otherwise it will match all other get requests.params['path']
in the pages#show
action.Start with the last segment and try to find it. If you don't find it, the page doesn't exist. If you get results for the last slug segment, check out their parants, if they match with the next slug segment and so on.
If it's going to be a huge tree, this solution probably creates a performance problem. Then you could implement something that stores the path somewhere or use solutions like the PostgreSQL ltree
.
Upvotes: 1