ruby-on-railsrubyruby-on-rails-5ancestry

Full Rails 5 routes with Ancestry Gem nested tree


I am using the Ancestry Gem in my Rails 5 app and all things look and act as they should and my database looks good. I just can't figure out out how to show the full url path after the first level following the model name.

For Example

I need http://127.0.0.1:3000/pages/29 to look like http://127.0.0.1:3000/pages/22/29 (I'll implement friendly ids after its working). In the above example, id:29 is a subpage of ancestry id:22

Screenshot of Database

enter image description here

page.rb

class Page < ApplicationRecord
  has_ancestry
end

pages_controller.rb

...
private
...
def page_params
 params.require(:page).permit(:name, :content, :ancestry, :slug, :parent_id)
end
...

schema.rb

create_table "pages", force: :cascade do |t|
  t.string "name"
  t.text "content"
  t.string "ancestry"
  t.string "slug"
  t.datetime "created_at", null: false
  t.datetime "updated_at", null: false
  t.index ["ancestry"], name: "index_pages_on_ancestry"
end

routes.rb

...
resources :pages
root to: 'pages#index'
...

127.0.0.1:3000/rails/info/routes

Helper  HTTP Verb   Path    Controller#Action
Path / Url      
Path Match
stripe_event_path       /webhooks/stripe    
StripeEvent::Engine

new_user_session_path   GET /users/sign_in(.:format)    
devise/sessions#new

user_session_path   POST    /users/sign_in(.:format)    
devise/sessions#create

destroy_user_session_path   DELETE  /users/sign_out(.:format)   
devise/sessions#destroy

new_user_password_path  GET /users/password/new(.:format)   
devise/passwords#new

edit_user_password_path GET /users/password/edit(.:format)  
devise/passwords#edit

user_password_path  PATCH   /users/password(.:format)   
devise/passwords#update

PUT /users/password(.:format)   
devise/passwords#update

POST    /users/password(.:format)   
devise/passwords#create

cancel_user_registration_path   GET /users/cancel(.:format) 
devise/registrations#cancel

new_user_registration_path  GET /users/sign_up(.:format)    
devise/registrations#new

edit_user_registration_path GET /users/edit(.:format)   
devise/registrations#edit

user_registration_path  PATCH   /users(.:format)    
devise/registrations#update

PUT /users(.:format)    
devise/registrations#update

DELETE  /users(.:format)    
devise/registrations#destroy

POST    /users(.:format)    
devise/registrations#create

users_path  GET /users(.:format)    
users#index

POST    /users(.:format)    
users#create

new_user_path   GET /users/new(.:format)    
users#new

edit_user_path  GET /users/:id/edit(.:format)   
users#edit

user_path   GET /users/:id(.:format)    
users#show

PATCH   /users/:id(.:format)    
users#update

PUT /users/:id(.:format)    
users#update

DELETE  /users/:id(.:format)    
users#destroy

pages_path  GET /pages(.:format)    
pages#index

POST    /pages(.:format)    
pages#create

new_page_path   GET /pages/new(.:format)    
pages#new

edit_page_path  GET /pages/:id/edit(.:format)   
pages#edit

page_path   GET /pages/:id(.:format)    
pages#show

PATCH   /pages/:id(.:format)    
pages#update

PUT /pages/:id(.:format)    
pages#update

DELETE  /pages/:id(.:format)    
pages#destroy

root_path   GET /   
pages#index

Routes for StripeEvent::Engine
root_path   POST    /   
stripe_event/webhook#event

Solution

  • Your Problem

    You want to perform a GET request /pages/:anchestry_id/:id for action pages#show

    Solution

    You need to add a special route at the top of your routes.rb file

    get '/pages/:anchestry_id/:id' => 'pages#show', as: 'page'
    

    You need to understand where you want to have that link, so from which pages in your app you want to call the action pages#show, because you will need to go to that controller action and in that action retrieve the 2 variables required for that link, which are @anchestry and @page

    If you are doing this from the pages#index, then you will have many links and you will have to query all the @ancestries and @pages then loop them in the view to create many links

    pages_controller.rb

    def index
        @ancestries = Ancestry.all
        @pages = Page.all
    end
    

    Then you need to add a link in the pages

    <%= link_to 'page', page_path(@ancestry, @page) %>
    

    Or in the case of the pages/index.html.erb, which will use @pages and @ancestries do

    <% @pages.each do |page| %>
         <%= link_to 'page', page_path(page.ancestry, page) %>
    <% end %>
    

    the problem is that as I see from your db, some entries have the ancestry as nil

    31 About us Description of company [Null]
    

    this will trigger a routes error, because you will be passing page.ancestry = nil and you can not have a route /pages/null/31

    So I believe you need to put your thought back together and think about the design of your app architecture.

    Also why passing the ancestry in your route? All this does not make sense