Rails respond_with acting different in index and create method

我只是一个虾纸丫 提交于 2019-12-18 11:48:05

问题


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?


回答1:


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




回答2:


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.




回答3:


I have found that errors = {:error => @device.errors.full_messages} respond_with( errors, :status => :bad_request, :location => nil) works. The :location is required and setting it to nil helps when using with spec: expect(last_response.status).not_to eql 201 expect(last_response.location).to be_nil

The problem I was having is that I was not returning the errors hash, just the status. Adding the errors hash and setting the location myself solved it.



来源:https://stackoverflow.com/questions/7303551/rails-respond-with-acting-different-in-index-and-create-method

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!