【问题标题】:Rails | nested routes if nil导轨 |如果为 nil,则嵌套路由
【发布时间】:2017-07-07 15:26:52
【问题描述】:

我使用了friendly_id 和globalize 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

我该怎么做?

【问题讨论】:

标签: ruby-on-rails controller routes nested-routes


【解决方案1】:

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

例子:

# 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 的每个请求中都涉及数据库并且如果存在数据库连接问题。

希望对您有所帮助。

【讨论】:

  • 感谢您的帮助!我想我会选择“稳定的解决方案”。一个问题。为什么要使用约束?
  • 当我说 rake 路线时,我看不到“范围到:'searches#show',约束:{rental_type:/(daily|weekly|monthly)/} 的路径.. "
  • 您需要使用约束来确保 Rails 参数解析器可以区分不同的参数。它只是防止 Rails 将“德国”解释为城市、将“柏林”解释为汽车类型等问题,并且在您开始添加其他组合时变得有用(例如,如果需求发生变化并且您需要添加另一个字段,例如 get '/search/:country/:city/:location/:rental_type' 其中位置是“机场”、“火车站”或其他)。现在可能没有必要,但它可以防止出现问题。
  • 至于rake routes 的问题:两条路线都未命名,因此它们可能会显示但它们没有名称 - 因此输出中的左侧部分未显示。跨度>
  • 多项选择: 1) 为它编写自己的 URL 助手 (def search_path(params = {})) 并手动编写 URL。 2) 将as: :searchas: :search_with_city 附加到路由中。 3) 手动将 URL 直接写入模板。我建议使用选项 1。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-29
相关资源
最近更新 更多