【问题标题】:Dynamic routes with Rails 3Rails 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)字段...但没有文档显示如何将其用于路由目的。欢迎提供任何帮助。问候。

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


【解决方案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】:

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

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

      2. :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

      希望对你有帮助!

      干杯

      【讨论】:

        猜你喜欢
        • 2012-06-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-03-02
        • 2016-05-22
        • 1970-01-01
        • 2014-11-08
        相关资源
        最近更新 更多