1

Custom routes for the same controller. I have many semi-static pages in my app (actually stored in my database with a group and page name field), they are grouped by product and then subject, for example Cars: tires, Wheels, Radio, Windshield Homes: Doors, Windows, Roof Products and Services: data services

I would prefer not to make a new controller for each group. However, I am trying to get different URL paths that are descriptive. For example:

domain.com/cars/tires_and_spokes
domain.com/cars/wheels
domain.com/homes/doors_and_knobs
domain.com/homes/windows
domain.com/products_and_services/data_service

currently, all I have is

domain.com/pages/cars_tires_and_spokes
etc.

but I prefer the former.

Routes:

   pages_from_DB =[ 
           {group:"cars", name:"tires and spokes"}
           {group:"cars", name:"wheels"}
           {group:"homes", name:"tires and spokes"}
           {group:"homes", name:"windows"}
           ]
   pages = %w[
               cars_tires_and_spokes
               cars_wheels
               homes_doors_and_knobs
               homes_windows
               products_and_services_data_service
             ]

   pages.each do |page|          
     get page, controller: "pages", action: page
   end

Controller:

class PagesController < ApplicationController

   pages_from_DB =[ 
       {group:"cars", name:"tires and spokes"}
       {group:"cars", name:"wheels"}
       {group:"homes", name:"tires and spokes"}
       {group:"homes", name:"windows"}
       ]
   pages = %w[
               cars_tires_and_spokes
               cars_wheels
               homes_doors_and_knobs
               homes_windows
               products_and_services_data_service
             ]

  pages.each do |page|          
    define_method(page) do 

    end
  end
end
user2012677
  • 5,465
  • 6
  • 51
  • 113

1 Answers1

2

Looks like you've missed the point of nested resources:

#config/routes.rb
resources :groups, path: "", only: [] do
   resources :pages, path: "" #-> url.com/:group_id/:id
end

This will direct any user to the pages controller, to which they're able to pull both the Group and ID from their respective models:

#app/controllers/pages_controller.rb
class PagesController < ApplicationController
   def show
      @group = Group.find params[:group_id]
      @page  = @group.pages.find params[:id]
   end
end

--

This should be accompanied by the following models:

#app/models/group.rb
class Group < ActiveRecord::Base
   has_many :pages
end

#app/models/page.rb
class Page < ActiveRecord::Base
   belongs_to :group
end

If you wanted to treat the routes with a slug (instead of id), you'll want to look at friendly_id:

#Gemfile
gem "friendly_id"

$ rails generate friendly_id
$ rails generate scaffold group title:string slug:string:uniq
$ rails generate scaffold page title:string slug:string:uniq 
$ rake db:migrate

#app/models/group.rb
class Group < ActiveRecord::Base
   has_many :pages

   extend FriendlyId
   friendly_id :title, use: [:slugged, :finders]
end

#app/models/page.rb
class Page < ActiveRecord::Base
   belongs_to :group

   extend FriendlyId
   friendly_id :title, use: [:slugged, :finders]
end

This will allow you to use:

<%= link_to group_pages_path(@group, @page) %>
# -> url.com/group-name/page-title

Update

The above code was based on the idea that you would be able to put your pages into the database (as you should). If you don't want to do that, there is a wildcard route you may be able to use:

#config/routes.rb
get "*group/:page", to: "pages#show"

If the pages were "semi-static" (still don't know what that means), you'd then be able to render the various views as required:

#app/controllers/pages_controller.rb
class PagesController < ApplicationController
   def show
      group = params[:group]
      render "#{params[:group]}/#{params[:page]"
   end
end

The above would give you the following link:

 url.com/path/to/your/group/this-is-the-page-id

Depending on your group / sub-group structure, it should give you the ability to call the various views. I don't agree with it but it's apparently what you wanted.

--

Custom Middleware

We also created custom middleware which has some of the functionality for this:

#config/routes.rb
get "*group/:page", to: PageDispatcher.new

#app/controllers/pages_controller.rb
class PagesController < ApplicationController
   cattr_accessor :pages #-> PagesController.pages
   @@pages = %w[
               cars_tires_and_spokes
               cars_wheels
               homes_doors_and_knobs
               homes_windows
               products_and_services_data_service
             ]
end

#lib/page_dispatcher.rb
class PageDispatcher

  #Init
  def initialize(router)
    @router = router
  end

  #Env
  def call(env)
    group    = env["action_dispatch.request.path_parameters"][:group]
    page     = env["action_dispatch.request.path_parameters"][:page]
    if PagesController.pages.include? page
      strategy(slug).call(@router, env)
    else
      raise ActiveRecord::RecordNotFound
    end
  end

  ##########################################

  private

  #Strategy
  def strategy(url)
    Render.new(url)
  end

  ####################

  #Render
  class Render

    def initialize(url)
      @url = url
    end

    def call(router, env)
      controller  = PagesController 
      action      = "show"
      controller.action(action).call(env)
    end

  end

  ####################

end
Richard Peck
  • 76,116
  • 9
  • 93
  • 147
  • I have semi-static pages, they don't get pulled from the database. The nested resources part is useful, but I need to figure out how to adapt to static pages. – user2012677 Jan 30 '16 at 14:03
  • When you say "semi-static", what do you mean? – Richard Peck Jan 30 '16 at 14:09
  • You meant they're populated with data set in the controller (not tied to a model)? – Richard Peck Jan 30 '16 at 14:10
  • To simplify things, think of all the pages as completely-static. If you look at my controller, I reference methods corresponding to the view name. As for the groups and categories, they could be listed in a hash like above, no database needed. I hope this helps – user2012677 Jan 30 '16 at 14:45
  • Sure, I just figured that if they were completely static, it would be far better to put them into the `pages` db, so that you just have to call the `show` action. That's why I posted what I did. I'll add a refactor for you now – Richard Peck Jan 30 '16 at 17:01
  • Updated for you, both recommendations route to the `PagesController` – Richard Peck Jan 30 '16 at 17:31
  • My pages tended to be completely different, with video or pictures, forms in different places. Which is why I made static pages that pages_controller would serve. I will look into adding "Tinymce" a WYSIWYG HTML editor to my activeadmin to store the contents of each page. and review your recommendation. thank you – user2012677 Jan 31 '16 at 12:53
  • No problem, it is by far better to use database-stored data than hard-coded. – Richard Peck Jan 31 '16 at 12:54