Rails 3 的动态路由

Posted

技术标签:

【中文标题】Rails 3 的动态路由【英文标题】:Dynamic routes with Rails 3 【发布时间】:2011-05-10 21:36:36 【问题描述】:

我的任务是按照路由模型开发 Rails 应用程序。

我需要有PageControllerPage 模型。页面 url 必须像 /contacts, /shipping, /some_page

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

并且它将是ProductsControllerProduct型号,产品的url必须是/laptops/toshiba_sattelite_l605/smartphones/android/htc_magic

我知道这个问题可以通过使用类似的 URL 来解决

/page/shipping /catalog/smartphones/android

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

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

【问题讨论】:

如何区分/something是页面还是类别? 可能是类别(/laptops),也可能是页面(/contacts)。当然,我知道类别和页面模型需要有一些字段,比如“slug”,并且它必须在站点中是唯一的。 这是一个非常糟糕的主意。如果他们担心网址“丑陋”,那么他们可以执行/faq/contacts/questions/shipping 之类的操作。 查看官方 Rails 路由指南@guides.rubyonrails.org/routing.html 你找到解决方案了吗?我也很感兴趣......但谷歌没有帮助我:(我使用友好的_id,它生成了一个带有 slug 名称的表 slug,它是 id 和控制器名称(sluggable_type)字段...但没有文档显示如何将其用于路由目的。欢迎提供任何帮助。问候。 【参考方案1】:

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

在此示例中,唯一的方法是通过smartphones 实际搜索页面,如果没有找到,则假定这是一个类别名称并搜索一个类别。这不能在铁路路线中完成。为此,您需要一个控制器来处理所有这些 URL 并进行搜索,然后呈现适当的模板(您不能重定向,因为这会更改 url)。这是解决这个问题的一种丑陋的方法。

如果我是你,我会尝试说服客户同意某种前缀(如 /p_pagename),或者最好是不同的 URL。对于页面,它可能类似于 /p/shipping,所有其他 URL 都可以路由到 CategoriesControllerProductsController

【讨论】:

我同意你的立场,但绝对不可能说服客户同意 URL 中的某种前缀。他的 SEO 需要这样的 URL。所以我需要找到解决方案。【参考方案2】:

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

在 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,也可以。

【讨论】:

仅根据示例进行投票 ;)【参考方案3】:

你需要写一个catch all

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 参数分开并在控制器中处理路径段

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

【讨论】:

【参考方案4】:

我发现这份 rails 3 路由指南非常有用:

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

【讨论】:

【参考方案5】:

我结合了两种方法来做到这一点

    使用 friendly_id gem 在查找请求中处理 slug 而不是数字 id

    :constraints=&gt;ConditionClass定义路由,它必须返回truefalse(所以路由将被确定或不)

小例子:

#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' =&gt; 'another_controller#another_action', :constraints=&gt;ConditionClassN

希望对你有帮助!

干杯

【讨论】:

以上是关于Rails 3 的动态路由的主要内容,如果未能解决你的问题,请参考以下文章

动态路由RIP

动态路由协议 RIP 协议

动态路由与静态路由

3.21下午

vue 实现动态路由

动态路由概述