Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails respond_with acting different in index and create method

I am building a simple json API in Rails 3.1. I created a controller that has two functions:

class Api::DogsController < ActionController::Base
  respond_to :json, :xml
  def index
    respond_with({:msg => "success"})
  end

  def create
    respond_with({:msg => "success"})
  end
end

In routes.rb I have

namespace :api do 
  resources :dogs
end

When I make a get request to http://localhost:3000/api/dogs I get the correct json from above. When I make a post to the same url, I get a rails exception:

ArgumentError in Api::DogsController#create
Nil location provided. Can't build URI.
actionpack (3.1.0) lib/action_dispatch/routing/polymorphic_routes.rb:183:in `build_named_route_call`
actionpack (3.1.0) lib/action_dispatch/routing/polymorphic_routes.rb:120:in `polymorphic_url'
actionpack (3.1.0) lib/action_dispatch/routing/url_for.rb:145:in `url_for'

But if I change the create code to

def create
  respond_with do |format|
    format.json { render :json => {:msg => "success"}}
  end
end

it returns the json just fine.

Can someone explain what is going on here?

like image 726
Thomas Tremble Avatar asked Sep 05 '11 03:09

Thomas Tremble


2 Answers

After coming across this issue myself and overcoming it, I believe I can supply an answer.

When you simply say:

def create
  respond_with({:msg => "success"})
end

What rails tries to do is "guess" a url that the newly created resource is available at, and place it in the HTTP location header. That guess fails miserably for a hash object (the location it deduces is nil, which leads to the error message you are seeing).

To overcome this issue, then, you would need to do the following:

def create
  respond_with({:msg => "success"}, :location => SOME_LOCATION)
end

Assuming that you know where the new resource is located. You can even specify "nil" as "SOME_LOCATION" and that will work (somewhat absurdly).

like image 171
Aubergine Avatar answered Oct 14 '22 00:10

Aubergine


I had the problem myself.

It is, like Aubergine says, something related with the http location header.

Actually, rails seems to build this location using by default the show route.

If you don't have a show action, -which is weird in an API, but can happen (i think)`, then you have to set a location by yourself. I have no idea what is the standard in this case.

If it happens that you need a show route, then code it, and everything should work fine.

Cheers.

like image 21
Pasta Avatar answered Oct 14 '22 02:10

Pasta