I am building a JSON API and so far I didn't find a good advice on how to handle save errors in controllers that use RABL templates. I'd really appreciate any advise on improving the code.
Here's how I currently handle a failure to save:
# products_controller.rb
def create
@product = Product.new(params[:product])
unless @product.save
render json: @product.errors, status: :unprocessable_entity
end
end
And here's my RABL template:
# product.json.rabl
object @product
attributes :name, :price
It works, but the line 'unless @product.save' doesn't feel right... Here are the tests:
# products_controller_test.rb
test 'create a product' do
assert_difference 'Product.count', 1 do
post :create, product: { name: 'Apple', price: 1.25 }, format: :json
end
assert_response :success
end
test 'failing product creation' do
Product.any_instance.stubs(:save).returns(false)
assert_no_difference 'Product.count' do
post :create, product: { name: 'Apple' }, format: :json
end
assert_response 422
end
Update
Thanks to @KonradOleksiuk I was able to rewrite the controller in a more readable way:
if @product.save
respond_with @product
else
respond_with @product, status: :unprocessable_entity
end
I also had to make sure errors were getting attached to the json response:
# product.json.rabl
object @product
attributes :name, :price
node :errors do |o|
o.errors
end
It depends a bit on format you would like to achieve in response. You can always use node
in rabl template to render errors inline. It has already been explained by collaborator of the gem: https://github.com/nesquena/rabl/issues/222#issuecomment-5413021
Thanks to this you can avoid the unless statement and use only view.