Fishtoaster
Fishtoaster

Reputation: 1819

Rails route only if resource is present

I want to have a rails route that triggers if the given id is present, but falls back to further route matching if not.

Specifically, I want to have promo codes at the root level of my site. So, you can go to foo.com/save87 or foo.com/xmasspecial, and it'll treat it as a promo code, but if you go to a promo code that's not there (foo.com/badcode), that route will not match and rails will continue down the route list.

In an ideal world, I'd do something like this in my routes.rb file:

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

I know that the above code, without the constraints, would work as a catch-all for foo.com/*, and would sorta work if I put it as the last line in the routes file. Unfortunately, that would result in foo.com/badcode a 'promocode not found' error, rather than a normal 'route not found' error.

So, is there a way to accomplish what I'm trying to accomplish? This is in Rails 3, for reference.


Edit: To clarify a bit-

Upvotes: 0

Views: 1497

Answers (2)

Paritosh Piplewar
Paritosh Piplewar

Reputation: 8122

In an ideal world, I'd do something like this in my routes.rb file:

No way. In Rails World, this functionality should go inside controller.

In controller you can do something like

def show
  if Promo.exists?(promo_id)
    #do something
  else
    raise ActionController::RoutingError.new('Not Found')
  end
end

Update

With routes, you can do something like this

constraints(lambda { |req| Promo.exists?(req.params["promo_id"]) }) do
    get '/:promo_id' => 'promos#show
end

Please keep in mind that this constraints will query the database for every request with a url matching the pattern /:promo_id (e.q. /users, /faq). To avoid unnecessary database queries that decrease your website performance, you should add this rule as far as possible to the end of your routes.rb.

Upvotes: 4

Austio
Austio

Reputation: 6075

Using this routing logic, every request to your application would do an extra search for a promo code before it moved on to the rest of the routes. I recommend looking at your business case and consider doing a Promo controller. If you must do routes, something like this would work but I would put it at the end so that it goes to your regular routes first.

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

Upvotes: 0

Related Questions