0

I have a basic Page model in Rails that I'm using with FriendlyId to allow admins to create pages like "/about" or "/contact".

I have the following in my routes file (config/routes.rb) to ensure that the slugs for each page appear at the root of the site, such as https://example.com/about, etc:

resources :pages, except: [:show]
resources :pages, only: [:show], path: "/"

The problem is, with this approach, I can't use the normal named route like page_path(@page) in my views(or tests or controllers for that matter) because that routes to "/pages/about" and I get a "No route matches [GET] pages/about" error.

I could do both routes in my routes file so that "/pages/about" and "/about" work like this:

resources :pages
resources :pages, only: [:show], path: "/"

But, that creates an SEO duplicate content problem. I suppose I could create a helper that sets the rel="canonical" url for each page in the html header, but that also feels like a hack. I'd prefer for there to just be 1 version of each page at the root and also have a named route such as "page_path" or "root_page_path" that I can use throughout my app.

The hack I've come up with for the time being is <%= link_to "#{page.slug}" %>, but not having a named route seems very brittle.

What is a more "correct" way to do this in Rails?

I expected something like this to work:

resources :pages, only: [:show], path: "/", as: "page"

But that doesn't work either. Nothing in the Rails guide on routing is really helping either.

Hristo Eftimov
  • 13,845
  • 13
  • 50
  • 77
Lee McAlilly
  • 9,084
  • 12
  • 60
  • 94

1 Answers1

0

You need top switch the order of their definitions:

resources :pages, only: [:show], path: "/"
resources :pages, except: [:show]

resources only give name to the first path with given url. However - you will have the problem now as the pages/:id path (for delete and update) has now no route helper (as it is normally the same as show).

EDIT: As mentioned in the comment - it will also automatically match /pages path to a show action with id equal to pages - not a great idea! Which leads to better option:

resources :pages, except: [:show]
get :id, to: "pages#show", as: :root_page

Which gives you root_page_path(@page) helper for :show action and page_path(@page) for :update and :delete

BroiSatse
  • 44,031
  • 8
  • 61
  • 86
  • 1
    The order here is actually wrong. You need to declare the index route first as `/pages` would end up getting routed to the show action. – max May 06 '21 at 22:09