For Reasons™, I want to have one controller handle html requests and another handle json api requests.
I've got this in my routes:
scope module: :api, as: :api do
constraints format: :json do
resources :users
end
end
constraints format: :html do
resources :users
end
This works great when the url sports a suffix: /users.json
goes through my Api::UsersController
à la api_users_path
; /users.html
goes through my UsersController
à la users_path
.
However this does not behave as expected when there is no suffix in the url. Implementing the constraints as lambda show things go wrong:
#=> visiting /users
scope module: :api, as: :api do
constraints ->(request){ puts "In api: #{request.format}"; request.format == :json } do
resources :users
end
end
constraints ->(request){ puts "In html: #{request.format}"; request.format == :html } do
resources :users
end
#=> In api: text/html
#=> (request.format == :json) => false
and yet it ends up in the api controller.
No fiddling with custom constraint classes or lambdas or anything prevents rails from selecting the first route defined if none of the constraints match.
I can't find a way to write a constraint that catches when the url lacks a suffix, and I don't feel as if I should have to–request.format == :html
reports true when I'm navigating to /users
. Why isn't the second constraint catching that?
Also, while I could "fix" this by changing the order of these two, I'd much rather know why my constraints aren't working right.
Does anyone know how to enforce these constraints differently to effectively switch on whatever the format is, not just the url suffix, or have an explicit constraint that accommodates no format suffix?
I don't think you need the second constraints block (the one for :html
). I think this should do what you want:
scope module: :api, as: :api do
constraints format: :json do
resources :users
end
end
resources :users
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With