仅当资源存在时Rails路由

时间:2014-04-05 22:38:48

标签: ruby-on-rails ruby ruby-on-rails-3 routes

我希望有一个rails路由,如果给定的id存在则触发,但如果不存在则返回到进一步的路由匹配。

具体来说,我希望在我的网站的根级别有促销代码。因此,您可以转到foo.com/save87foo.com/xmasspecial,它会将其视为促销代码,但如果您转到不在那里的促销代码(foo.com/badcode),那么该路线将不匹配,rails将继续沿着路由列表。

在理想的世界中,我会在routes.rb文件中执行以下操作:

get '/:promo_id' => 'promos#show, constraints => lambda { Promo.exists?(promo_id) }

我知道上面的代码,没有约束,可以作为foo.com/*的全能,如果我把它作为路由文件中的最后一行,它会工作。不幸的是,这会导致foo.com/badcode'找不到promocode'错误,而不是正常的'找不到路线'错误。

那么,有没有办法完成我想要完成的任务?这是在Rails 3中,供参考。


编辑:澄清一点 -

  • 我想要一个如上所述的通配符网址,以便我们的促销代码网址简短且令人难忘(foo.com/save87代替foo.com/promo_codes/save87
  • 我希望在此之后可以选择其他路线。在某些时候,我可能需要在根级别使用另一个通配符网址 - 例如,如果我想在我的系统中使用另一个资源的虚荣URL。例如,如果我销售十几种小部件,除了我的促销代码网址之外,我可能还需要foo.com/widget_deluxefoo.com/widget_extreme等。我必须确保促销代码和小部件品种之间没有冲突,但这很容易在其他地方处理。

2 个答案:

答案 0 :(得分:4)

  

在一个理想的世界里,我在我的routes.rb文件中做了类似的事情:

没办法。在Rails World中,此功能应该在控制器内部。

在控制器中,您可以执行类似

的操作
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匹配的每个请求(e.q。/users/faq)查询数据库。为避免不必要的数据库查询降低网站性能,您应尽可能将此规则添加到routes.rb的末尾。

答案 1 :(得分:0)

使用此路由逻辑,对应用程序的每个请求都会在转到其他路由之前对促销代码进行额外搜索。我建议您查看您的业务案例并考虑使用Promo控制器。如果你必须做路线,这样的事情会起作用,但我会把它放在最后,以便它首先进入你的常规路线。

get '*', to: 'promos#show'