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 在以下情况下严重失败,那么它也会付出代价数据库连接有问题。
希望对您有所帮助。
我用过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 在以下情况下严重失败,那么它也会付出代价数据库连接有问题。
希望对您有所帮助。