描述性URL,不同页面,但相同的控制器(domain.com/cars/wheels)

时间:2016-01-30 12:45:58

标签: ruby-on-rails ruby-on-rails-4 controller routes nested-routes

同一控制器的自定义路由。我的应用程序中有许多半静态页面(实际上存储在我的数据库中,包含组和页面名称字段),它们按产品分组,然后按主题分组,例如 汽车:轮胎,车轮,收音机,挡风玻璃 家园:门,窗户,屋顶 产品和服务:数据服务

我不想为每个组制作新的控制器。但是,我试图获得描述性的不同URL路径。例如:

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

目前,我所拥有的只是

domain.com/pages/cars_tires_and_spokes
etc.

但我更喜欢前者。

路线:

   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

控制器:

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

1 个答案:

答案 0 :(得分:2)

看起来你已经错过了nested resources

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

这会将任何用户定向到pages控制器,他们可以从他们各自的模型中提取GroupID

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

-

这应该伴随以下模型:

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

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

如果您想使用slug(而不是id)处理路线,则需要查看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

这将允许您使用:

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

<强>更新

上面的代码基于这样的想法,即您可以将pages放入数据库中(如您所愿)。如果您不想这样做,

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

如果页面是“半静态的”(仍然不知道这意味着什么),那么您就可以根据需要呈现各种视图:

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

以上内容将为您提供以下链接:

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

根据您的组/子组结构,它应该能够调用各种视图。我不同意它,但它显然是你想要的。

-

自定义中间件

我们还创建了具有部分功能的自定义中间件:

#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