我想要一条轨道路由,如果给定的 id 存在,则触发,但如果不存在,则回退到进一步的路由匹配。
具体来说,我想在网站的根级别设置促销代码。 因此,您可以转到 foo.com/save87
或 foo.com/xmasspecial
,它会将其视为促销代码,但如果您转到不存在的促销代码(foo.com/badcode
),该路线将不匹配,轨道将继续沿着路线列表。
在理想的世界中,我会在我的routes.rb
文件中做这样的事情:
get '/:promo_id' => 'promos#show, constraints => lambda { Promo.exists?(promo_id) }
我知道上面的代码,没有约束,可以作为foo.com/*
的全部内容,如果我把它放在路由文件中的最后一行,就会有点工作。 不幸的是,这将导致foo.com/badcode
"找不到促销代码"错误,而不是正常的"找不到路由"错误。
那么,有没有办法完成我想要完成的事情呢? 这是在 Rails 3 中,供参考。
编辑:澄清一点-
- 我想要一个如上所述的通配符网址,以便我们的促销代码网址简短而令人难忘(
foo.com/save87
而不是foo.com/promo_codes/save87
) - 我更愿意在此之后选择其他路线。 在某些时候,我可能需要根级别的另一个通配符 URL - 例如,如果我想要系统中另一个资源的虚 URL。 例如,如果我销售十几种小部件,除了我的促销代码 url 之外,我可能还需要
foo.com/widget_deluxe
、foo.com/widget_extreme
等。 我必须确保促销代码和小部件品种之间没有冲突,但这在其他地方很容易处理。
在理想的世界中,我会在我的routes.rb文件中做这样的事情:
不可能。在Rails
世界中,此功能应位于控制器内部。
在控制器中,您可以执行以下操作
def show
if Promo.exists?(promo_id)
#do something
else
raise ActionController::RoutingError.new('Not Found')
end
end
更新
使用路由,您可以执行以下操作
constraints(lambda { |req| Promo.exists?(req.params["promo_id"]) }) do
get '/:promo_id' => 'promos#show
end
请记住,此约束将查询数据库以获取与模式/:promo_id
匹配的 url 的每个请求(例如 /users
,/faq
)。为避免不必要的数据库查询降低网站性能,应将此规则尽可能添加到routes.rb
末尾。
使用此路由逻辑,对应用程序的每个请求都会在移动到其余路由之前对促销代码进行额外搜索。 我建议您查看您的业务案例并考虑使用促销控制器。 如果你必须做路线,这样的事情会起作用,但我会把它放在最后,以便它首先进入你的常规路线。
get '*', to: 'promos#show'