Rails |嵌套路由如果为零

Rails | nested routes if nil

我用过friendly_id和全球化gem。所以我可以将路线生成为;

/search/france/weekly/toyota-95

这是我的路线;

namespace :search do
  resources :car_countries, path: '', only: [] do
    resources :rental_types, path: '', only: [] do
      resources :car_types, path: '', only: [:show] do
      end
    end
  end  
end

但问题是现在我也想得到城市;

/search/nice/weekly/toyota-95

/search/france/nice/weekly/toyota-95

问题是我想要有城市名称和没有城市名称(只有国家)。他们应该去 car_types.

末尾的同一个控制器

因此,如果我将 car_cities 添加到路线,当没有城市而只有国家时,我会出错。

namespace :search do
 resources :car_countries, path: '', only: [] do
    resources :car_cities, path: '', only: [] do
       resources :rental_types, path: '', only: [] do
         resources :car_types, path: '', only: [:show] do
         end
       end
     end  
  end  

  resources :car_countries, path: '', only: [] do
    resources :rental_types, path: '', only: [] do
      resources :car_types, path: '', only: [:show] do
      end
    end
  end  
end

我该怎么做?

正如 Gerry 所说,看看路由通配 http://guides.rubyonrails.org/routing.html#route-globbing-and-wildcard-segments。我建议将所有内容发送到单个控制器操作,然后在那里执行操作或将其委托给搜索 model/service 对象(取决于您的口味)。

示例:

# in config/routes.rb
get 'search/*q' => 'searches#show'

# in app/controllers/searches_controller.rb
class SearchesController < ApplicationController
  def search
    # This should work for your simple use case but it will become pretty confusing if you add more filters.

    search_params = params[:search].split('/')
    if search_params.count == 4
      country, city, rental_type, car_type = search_params
    else
      country, rental_type, car_type = search_params
    end

    # Do whatever with these variables, e.g. Car.for_country(country)...
  end
end

一个更稳定的解决方案是利用租赁类型可能是一个封闭集(每天、每周……)这一事实,并在路线中对这部分使用分段约束:

# config/routes.rb
scope to: 'searches#show', constraints: { rental_type: /(daily|weekly|monthly)/ } do
  get '/search/:country/:rental_type/:car_type'
  get '/search/:country/:city/:rental_type/:car_type'
end

这应该根据 :city 永远无法匹配租赁类型限制这一事实来区分两个 URL。

另一种选择是使用完整的约束对象 (http://guides.rubyonrails.org/routing.html#advanced-constraints):

# config/routes.rb
class SearchConstraint
  def initialize
    # assuming that all your objects have the friendly_id on the name field
    @country_names = %w[austria germany]
    @rental_type_names = %w[daily weekly monthly]
    @car_type_names = %w[toyota-prius vw-golf]
    @city_names = %w[innsbruck munich berlin]
  end

  def matches?(request)
    checks = []

    # only check for parts if they're actually there
    checks << @country_names.include?(request.parameters[:country]) if request.parameters[:country].present?
    checks << @rental_type_names.include?(request.parameters[:rental_type]) if request.parameters[:rental_type].present?
    checks << @car_type_names.include?(request.parameters[:car_type]) if request.parameters[:car_type].present?
    checks << @city_names.include?(request.parameters[:city]) if request.parameters[:city].present?

    checks.all? # or, if you want it more explicit: checks.all? { |result| result == true }
  end
end

scope to: 'searches#show', constraints: SearchConstraint.new do
  get '/search/:country/:rental_type/:car_type'
  get '/search/:country/:city/:rental_type/:car_type'
end

请注意,这最后一种方法可能是最简洁、最简单的方法(而且它很容易测试),但如果在对这些特定 URL 的每个请求中都涉及数据库,并且 URL 在以下情况下严重失败,那么它也会付出代价数据库连接有问题。

希望对您有所帮助。