Ruby on rails URL中用于显示操作的自定义参数

Ruby on rails URL中用于显示操作的自定义参数,ruby-on-rails,ruby,ruby-on-rails-3,routing,seo,Ruby On Rails,Ruby,Ruby On Rails 3,Routing,Seo,我正在努力实现SEO hiarchy,这意味着我需要为show action预先设置参数 用例是一个URL结构为: /cars/(:brand)/=>列表页 /cars/(:brand)/(:model\u name)?s=query\u params=>搜索操作 /cars/:brand/:model_name/:variant/:id=>车展活动 我的问题是使show-action URL工作,而不必提供:brand、:model\u name和:variant作为单独参数。它们始终作为资源

我正在努力实现SEO hiarchy,这意味着我需要为show action预先设置参数

用例是一个URL结构为:
/cars/(:brand)/
=>列表页
/cars/(:brand)/(:model\u name)?s=query\u params
=>搜索操作
/cars/:brand/:model_name/:variant/:id
=>车展活动

我的问题是使show-action URL工作,而不必提供
:brand
:model\u name
:variant
作为单独参数。它们始终作为资源上的值从中可用

我所拥有的:
/cars/19330-Audi-A4-3.0-TDI

我想要什么
/cars/Audi/A4/3.0-TDI/19330

以前,
routes.rb
就是这样的:

# Before
resources :cars. only: [:show] do
  member do
  get 'favourize'
  get 'unfavourize'
end
以下是我的第一次尝试:

# First attempt
scope '/cars/:brand/:model_name/:variant' do
  match ":id" => 'cars_controller#show'
  match ":car_id/favourize" => 'cars_controller#favourize', as: :favourize_car
  match ":car_id/unfavourize" => 'cars_controller#unfavourize', as: :unfavourize_car
end
这样做就有可能:
cars\u路径(汽车,品牌:car.brand,车型名称:car.model\u名称,变体:car.variant)

但这显然并不理想

如何设置路由(可能还有
.to_param
方法?)而不使更改所有
link_to
调用成为一项繁琐的任务

提前谢谢

--更新--

根据@tharrisson的建议,我尝试了以下几点:

# routes.rb
match '/:brand/:model_name/:variant/:id' => 'cars#show', as: :car

# car.rb
def to_param
  # Replace all non-alphanumeric chars with - , then merge adjacent dashes into one
  "#{brand}/#{model_name}/#{variant.downcase.gsub(/[^[:alnum:]]/,'-').gsub(/-{2,}/,'-')}/#{id}"
end
路线运行正常,例如,
/cars/Audi/A4/3.0-TDI/19930
显示正确的页面。但是,使用
生成指向_param
的链接不起作用。例如:

link_to "car link", car_path(@car)
#=> ActionView::Template::Error (No route matches {:controller=>"cars", :action=>"show", :locale=>"da", :brand=>#<Car id: 487143, (...)>})
link_to "car link 2", car_path(@car, brand: "Audi")
#=> ActionView::Template::Error (No route matches {:controller=>"cars", :action=>"show", :locale=>"da", :brand=>"Audi", :model_name=>#<Car id: 487143, (...)>})
link_到“car link”,car_路径(@car)
#=>ActionView::Template::Error(没有路线匹配{:controller=>“cars”,:action=>“show”,:locale=>“da”,:brand=>#})
链接至“汽车链接2”,汽车路径(@car,品牌:“奥迪”)
#=>ActionView::Template::Error(没有路线匹配{:controller=>“cars”,:action=>“show”,:locale=>“da”,:brand=>“Audi”,:model_name=>#})

Rails似乎不知道如何将to_参数转换为有效链接。

好的,下面是我得到的。这在我的小测试用例中有效。显然需要一些修饰,我相信可以更简洁优雅,但我的座右铭是:“让它工作,让它漂亮,让它快速”:

routes.rb中

  controller :cars do
    match 'cars', :to => "cars#index"
    match 'cars/:brand', :to => "cars#list_brand", :as => :brand
    match 'cars/:brand/:model', :to => "cars#list_model_name", :as => :model_name
    match 'cars/:brand/:model/:variant', :to => "cars#list_variant", :as => :variant
  end
  def index
    @cars = Car.all

    respond_to do |format|
      format.html # index.html.erb
      format.json { render json: @cars }
    end
  end

  def list_brand
    @cars = Car.where("brand = ?", params[:brand])

    respond_to do |format|
      format.html { render :index }
    end
  end

  def list_model_name
    @cars = Car.where("brand = ? and model_name = ?", params[:brand], params[:model])

    respond_to do |format|
      format.html { render :index }
    end
  end

  def list_variant
    @cars = Car.where("brand = ? and model_name = ? and variant = ?", params[:brand], params[:model], params[:variant])

    respond_to do |format|
      format.html { render :index }
    end
  end
在汽车模型中

  def to_param
    "#{brand}/#{model_name}/#{variant}"
  end
而且明显易碎且不干燥,在
cars\u controller.rb中

  controller :cars do
    match 'cars', :to => "cars#index"
    match 'cars/:brand', :to => "cars#list_brand", :as => :brand
    match 'cars/:brand/:model', :to => "cars#list_model_name", :as => :model_name
    match 'cars/:brand/:model/:variant', :to => "cars#list_variant", :as => :variant
  end
  def index
    @cars = Car.all

    respond_to do |format|
      format.html # index.html.erb
      format.json { render json: @cars }
    end
  end

  def list_brand
    @cars = Car.where("brand = ?", params[:brand])

    respond_to do |format|
      format.html { render :index }
    end
  end

  def list_model_name
    @cars = Car.where("brand = ? and model_name = ?", params[:brand], params[:model])

    respond_to do |format|
      format.html { render :index }
    end
  end

  def list_variant
    @cars = Car.where("brand = ? and model_name = ? and variant = ?", params[:brand], params[:model], params[:variant])

    respond_to do |format|
      format.html { render :index }
    end
  end

如果不调整URL识别或URL生成,我看不到任何使用Rails实现这一点的方法

第一次尝试时,URL识别工作正常,但无法生成。我能看到的使生成工作的解决方案是重写
car\u path
helper方法

另一个解决方案可能是,就像您在更新中所做的那样,覆盖Car的
to_param
方法。请注意,您的问题不在
to_param
方法中,而是在路由定义中:当您要生成路由时,需要给出
:brand
:model_name
:variant
参数。为了解决这个问题,你可能需要在你的路线上使用a

最后,您还可以使用,这使您能够在url识别/生成之前和之后添加逻辑


对我来说,看起来所有这些解决方案都有点繁重,并不像应该的那么简单,但我相信这是出于您的需要,因为您希望在URL中添加一些级别,而不严格遵循rails行为,这将为您提供URL,如
/brands/audi/models/A3/variants/19930

您希望将有界参数传递到其中有些参数是可选的,有些参数需要严格显示

Rails指南显示,您可以有严格的和可选的参数,还可以为特定的路由命名,以简化其使用

铁路路线指南

示例用法-

在下面的路线中

  • 品牌
    可选参数
    ,因为它被
    圆形括号包围
  • 另外请注意,路线内可能有可选参数,但它们需要在最后添加
    /cars(/:brand)(/:make)(/:model)

    match'/cars/(:brand);:to=>“cars#index”;:as=>cars

这里
cars\u url
将映射到cars控制器的索引操作。。 同样地,
cars\u url(“Totoya”)
将把cars控制器的索引动作与
params[:brand]
as
Toyota

显示url路由可以如下所示,其中id是必需的,其他可以是可选的

match '/cars/:id(/:brand(/:model_name/)(/:variant)', :to => "cars#show", :as => car
在上述情况下,
id
是必填字段。其他参数是可选的。
因此,您可以像
car\u url(car.id)
car\u url(12,'toyota')
car\u url(12,'toyota','fortuner')
car\u url(12,'toyota','fortuner','something)
您只需要创建两条路线,一条用于识别,一条用于生成

更新:使用有问题的路线

#config/routes.rb
#这个用于路径生成
资源:cars,:only=>[:index,:show]do
成员do
得到“宠爱”
得到“不利”
结束
结束
#这个用于路径识别
范围“/cars/:brand/:model_name/:variant”do
匹配“:id(/:action)=>“cars#show”,:via=>:get
结束
并将
自定义为_param

#app/models/car.rb
需要“cgi”
类Car
路径帮助程序示例:

链接到“显示”,车辆路径(@car)
链接到“编辑”,编辑车路径(@car)
链接到“收藏夹”,收藏夹车路径(@car)
链接到“不利”,不利车辆路径(@car)
链接到“汽车”,汽车路径
(@car)的表单#如果资源:cars不是