使用Rails 3的动态路由

时间:2010-11-16 15:39:11

标签: ruby-on-rails ruby ruby-on-rails-3 url-routing

我有一项任务是按照路由模型开发rails应用程序。

我需要PageControllerPage型号。网页网址必须与/contacts, /shipping, /some_page相似。

我还需要CatalogControllerCategory型号。类别网址必须与/laptops, /smartphones/android类似。

它将是ProductsControllerProduct型号,产品网址必须为/laptops/toshiba_sattelite_l605行,/smartphones/android/htc_magic

我了解使用

等网址可以解决此问题
  • /page/shipping
  • /catalog/smartphones/android

但客户不希望在网址中看到“/page”或“/catalog”的插入。

请告诉我解决这个问题的方向。 抱歉我的英语不好。

5 个答案:

答案 0 :(得分:49)

你必须写一个“包罗万象”的规则:

在routes.rb上:

get '*my_precioussss' => 'sauron#one_action_to_rule_them_all'

贵重的控制者:

class SauronController < ApplicationController
  def one_action_to_rule_them_all
    @element = find_by_slug(params[:my_precioussss])
    render @element.kind # product, category, etc
  end
end

然后为每个元素的“种类”写一个视图:product.html.erb,category.html.erb等。

确保编写find_by_slug实施。

您可以将one_action_to_rule_them_all更改为pikachu_i_choose_you,将SauronController更改为PokemonController也可以。

答案 1 :(得分:4)

你需要写一个全部的

match '*page' => 'pages#show'

然后处理页面控制器中的页面路径

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

如果您使用Omniauth或其他使用它自己捕获的rails lib,您可能需要从中排除一些URL,在约束中使用lambda

match '*page' => 'pages#show', :constraints => lambda{|req|  !req.env["REQUEST_URI"].include? "auth"}

如果你想拥有嵌套路径(例如“smartphones / android”),你需要将:page param分开并处理控制器中的路径段

path = :page.split("/")  // you now have an array of path segments you can use in your controller

答案 2 :(得分:1)

我发现rails 3路由指南非常有帮助:

http://www.engineyard.com/blog/2010/the-lowdown-on-routes-in-rails-3/

答案 3 :(得分:1)

我已经结合两种方法完成了它

  1. 使用friendly_id gem在查找请求中使用slug而不是数字ID

  2. 定义:constraints=>ConditionClass的路由,必须返回truefalse(因此路由将被确定)

  3. 小例子:

    #routes.rb
        class CategoryBrandGoodConstraint
          def self.matches?(request)
            path_parts = request.path.split('/')
            Category.find(path_parts[1]).present?&&Brand.find(path_parts[2]).present?&&Good.find(path_parts[3]).present? rescue false
          end
        end
    
        get ':category_friendly_id/:brand_friendly_id/:good_friendly_id' => 'goods#index', :constraints => CategoryBrandGoodConstraint
        #another conditional routes with another :constraints=>ConditionClass2 definition
        #...
        #until you define all necessary conditional application routes
    
    #goods_controller.rb
    
        def index
    
          #operate with params[:category_friendly_id], params[:brand_friendly_id], params[:good_friendly_id] to collect all you need for view rendering
    
        end
    

    当然,您可以路由到另一个控制器以呈现另一个视图get '/:whatever' => 'another_controller#another_action', :constraints=>ConditionClassN

    希望它有所帮助!

    欢呼声

答案 4 :(得分:0)

Rails路由仅基于URL。如果您在名称之前没有/pages/categories或其他任何内容,那么Rails如何判断http://example.com/smartphones之类的网址是否为网页网址或类别网址?除非您在路线条件中有一些预定义的页面名称列表,否则它不能。

在此示例中,唯一的方法是按smartphones实际搜索页面,如果没有找到,则假设这是类别名称并搜索类别。这不能在rails路由中完成。要做到这一点,你需要一个控制器来处理所有这些URL并进行搜索,然后渲染一个合适的模板(你不能重定向,因为这会改变网址)。这是解决这个问题的一种丑陋方式。

如果我是你,我会试图说服客户就某种前缀(如/p_pagename)或最好是不同的网址达成一致。它可能类似/p/shipping页面,所有其他网址可以路由到CategoriesControllerProductsController