Search code examples
ruby-on-railsjsonapirabl

Responding with error using RABL template


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

Solution

  • 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.