Question

I'm trying to implement semi-static pages as per this railscast

At first I named my class 'About', but that threw the following error:

Invalid route name, already in use: 'page' (ArgumentError) You may have defined two routes with the same name using the :as option, or you may be overriding a route already defined by a resource with the same naming.

After some googleing, it seemed like it was conflicted with active_admin for some reason, so I rename the table to 'Page' and I've carefully renamed all the appropriate files, classes and methods etc. from 'About' to 'Page'

This is my Page model:

    class Page < ActiveRecord::Base

      validates_uniqueness_of :url

      def to_param
        url
      end   

    end

And these are my routes:

  get 'signup', to: 'users#new', as: 'signup'
  get 'login', to: 'sessions#new', as: 'login'
  get 'logout', to: 'sessions#destroy', as: 'logout'

  devise_for :admin_users, ActiveAdmin::Devise.config
  ActiveAdmin.routes(self)
  resources :users 
  resources :sessions
  resources :password_resets
  resources :posts do 
    resources :comments
    resources :votes, only: [:new, :create]
    resources :flags, only: [:new, :create]
  end
  resources :comments do 
    resources :comments
    resources :votes, only: [:new, :create]
    resources :flags, only: [:new, :create]
  end
  resources :newsletters
  resources :pages, except: :show
  resources :subscribers, only: [:index, :new, :create] 
  # resources :prelaunch
  # get 'about', to: 'prelaunch#about'
  root to: 'posts#index' 
  get ':id', to: 'pages#show', as: :page  

I'm still getting the same error as described above.

The only way I can get it to half-work is by dropping the 'as: :page' bit, which stops the conflict, and hardcoding the url I want to point to into the code e.g.

<%= link_to page.name, "localhost:3000/#{page.url}" %>

which is far from ideal.

I can't find any help in Routing from the Outside In.

Could anyone help?

Was it helpful?

Solution 3

Ok, after a lot of hacking around and a helpful pointer from Rich Peck, I've got a working solution.

Routes:

  resources :pages, except: :show
  if Page.all.any?
    Page.all.each do |page|
       get "#{page.url}", to: "pages#show", as: "#{page.url}", id: page.id
      end
  end

Controller:

  def show
    @page = Page.find(params[:id])
  end

Note, I've used the friendly_id gem as suggested.

To dynamically generate links:

Application controller:

  def about_us
    @pages = Page.all
  end
  helper_method :about_us

Pages helper:

def about_link(page)
    link_to page.name, "/#{page.url}"
end

NB: - you need to include the / otherwise it will try to prepend the name of the controller for the page you're on (I'm not sure why).

My footer:

<% about_us.each do | page | %>
<%= about_link(page) %>
<% end %>

UPDATE:

I've had a lot of trouble deploying my app to Heroku, and I believe it's because of the pages routes.

I've now changed to a much simpler solution:

  resources :pages, path: ""

and the problem's have gone away.

OTHER TIPS

Here's the fix:

#config/routes.rb
resources :pages, except: :show

(remove get ':id', to: 'pages#show', as: :page)

This will create the standard RESTful routes, which will create a routing structure except the show action


Slugs

How to create app-wide slug routing for Rails app?

If you want to have /about etc, you'll have to generate them specifically:

#config/routes.rb
if Page.all.any?
    Page.all.each do |page|
       get page, to: "pages#show", id: page.id
    end
end

This can also be handled with friendly_id

Have you considered using a gem that "does the work for you"? I've been using the https://github.com/thoughtbot/high_voltage gem to take care of static pages for me, without any hassle. It takes care of both routing and controller, only leaving the creation of the pages in a dedicated view/pages folder. Linking to a static page is as simple as creating a link to page_path(:name_of_the_page)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top