in routes.rb
MyAwesomeSite::Application.routes.draw do namespace :api do namespace :v1 do resources :topics end end end
in app/controllers/api/v1/topics_controller.rb
class API::V1::TopicsController < API::V1::APIController
def create
respond_with Topic.create(params[:topic])
end
end
This unfortunately won’t work, as it is going to complain about the missing topic_url helper.
Instead I’ll have to do this:
class API::V1::TopicsController < API::V1::APIController
def create
topic = Topic.create(params[:topic])
respond_with topic, location: api_v1_topic_url(topic)
end
end
But this still won’t work, because when there are validation errors in topic, api_v1_topic_url will raise an exception. So you’ll need…
class API::V1::TopicsController < API::V1::APIController
def create
topic = Topic.build(params[:topic])
if topic.save
respond_with topic, location: api_v1_topic_url(topic)
else
respond_with topic
end
end
end
…which almost defeats the purpose of using respond_with in the first place.
Did I miss any obvious solution? If not, I’d like to see improve this. I have a few ideas:
-
In the URL helpers, return nil instead of raising an exception
-
Accept a proc for the location option in respond_with. Since respond_with won’t even look at the location option when there are errors in the object passed in, the proc will only be called when the object was saved successfully and thus avoids the exception in the url helper:
class API::V1::TopicsController < API::V1::APIController
def create
topic = Topic.create(params[:topic])
respond_with topic, location: ->{ api_v1_topic_url(topic) }
end
end
- Respect the controller’s namespace when constructing the location object, so it will try to use api_v1_topic_url, api_topic_url and topic_url in that order.
My favourite is #3, but I’d have to do some research to find out how to do this or if it’s possible at all. Any comments / feedback / pointers are welcomed!
Godfrey