Seems like this answer provides a good solution. For example,
class FoosController < ActionController::Base
respond_to :json
class ApiResponder < ActionController::Responder
def to_format
case
when has_errors?
controller.response.status = :unprocessable_entity
when get? && !resource
controller.response.status = :not_found
when post?
controller.response.status = :created
end
default_render
rescue ActionView::MissingTemplate => e
api_behavior(e)
end
end
self.responder = ApiResponder
def show
@foo = Foo.find(params[:id])
@foo.errors.add(:base, "foo bar") # e.g. of errors on the object
respond_with @foo
end
end
Although the wiki has a warning that "setting controller.response.status
is like a default value", respond_with
or render
shouldn't explicitly set status
and it seems like a call to render "my_template"
triggers that 200
you mentioned. If you do want to reuse a single error template, something like the author's suggested template, this works:
...
self.responder = ApiResponder
def show
@foo = Foo.find(params[:id])
@foo.errors.add(:base, "foo bar") # e.g. of errors on the object
respond_with @foo do |format|
if @foo.errors.empty?
flash[:notice] = 'Foo was successfully created.'
else
format.json { render "error" }
end
end
end
# error.rabl
object false
node :errors do
{
:message => "Sorry, fubar'ed",
:code => 12345
}
end
This works with actions that write as well as read. The original bug discussion also has some interesting examples.