ruby-on-rails-3 - Rails respond_with——为什么 POST 返回的是 URL 而不是数据?

标签 ruby-on-rails-3 json rest respond-to

这是一个“为什么它会这样工作”的问题,而不是“我如何让这个工作”。

我的应用程序正在调用返回 JSON 的第三方 REST API,并将结果作为我自己的 JSON API 的一部分返回。

我使用的是 Rails 3 respond_torespond_with方法;在 GET 的情况下请求,这按我的预期工作,只是通过 JSON。

POST 的情况下,它做的更多,包括从返回的对象中创建一个 URL 以传入 :location选项。但由于我的对象只是 JSON(不是 ActiveRecord),我得到一个错误。

例如...

# POST /api/products.json with params id=:id
def create
  query_string = "#{user_id}&id=#{params[:id]}"
  @products = third_party_api_wrapper.products(query_string, 'POST')
  respond_with @products
end 

我的第 3 方 API 包装器发出一个 POST 请求,该请求返回正常,然后 Rails 返回一个 500 错误,记录如下:
NoMethodError (undefined method `{"response":{"message":"product 4e1712d9ec0f257c510013f8 selected"}}_url' for #<MyController> 

Rails 希望我的 @products 对象知道如何创建位置 URL。

澄清:@products第三方 API 返回的对象是纯 JSON —— 一个字符串,您可以在上面的错误日志消息中看到该字符串。发生此错误是因为 Rails 似乎希望对象更多——在 Rails 内部 API 支持中,它是一个 ActiveRecord 对象。

如果我更换新的 respond_with带有旧式的语法
respond_to do |format|
  format.json { render :json => @products }  # note, no :location or :status options
end

然后一切正常。这就是我所做的,所以我没有“如何”的问题,而是有一个“为什么”的问题。

Ryan Daigle's post在介绍中解释说,正在发生的事情是意料之中的。

我的问题是:为什么 respond_with期望除数据(和 HTTP 状态?)之外的任何东西,显然只是为了 POST .

我不是说错了,只是试图理解 Rails 实现的基本原理。

最佳答案

简介:Rails 的基本原理来自 HTTP 和 REST。
(感谢您更新的问题。现在我理解了您的核心问题:“我并不是说这是错误的,只是想了解 Rails 实现的基本原理。”)
现在解释一下。 Rails 行为的基本原理 Root 于接受 HTTP 和 REST 约定。
只是为了从您所读到的内容与我将要详细说明的内容联系起来,我想提一下 Ryan Daigle's article on Default RESTful Rendering 中的相关部分:

If the :html format was requested:

[some text removed]

  • [after PUT or POST and no validation errors] redirect to the resource location (i.e. user_url)

([括号中的]文字是我添加的。)

If another format was requested, (i.e. :xml or :json)

[some text removed]

  • If it was a POST request, invoke the :to_format method on the resource and send that back with the :created status and the :location of the new created resource"

让我用我的话说,Rails 认为是好的做法:
  • 对于人类内容(例如 HTML),在 POST 或 PUT 之后,服务器应该告诉浏览器通过 303 重定向到新创建的资源。这是一种常见的做法——非常有用,因为用户希望看到他们的编辑产生的更新。
  • 对于机器内容(例如 JSON、XML),在 PUT 之后,服务器应该只呈现 201 .客户端,在这种情况下,是一个使用 API 的程序,可能决定停在那里。 (毕竟,客户端指定了请求并得到了 201,所以一切都是 honky dory。)这就是为什么使用 201(成功)而不是 303(重定向)的原因。如果客户端想要请求新创建的资源,它可以使用 Location header 查找它——但不应强制重定向。

  • 在任何一种情况下,请注意新创建资源的位置是必需的。这就是为什么@products在您上面的示例中,需要同时包含数据和位置。
    作为背景,我分享了一些来自 W3C Page on 201 Created :

    10.2.2 201 Created

    The request has been fulfilled and resulted in a new resource being created. The newly created resource can be referenced by the URI(s) returned in the entity of the response, with the most specific URI for the resource given by a Location header field. The response SHOULD include an entity containing a list of resource characteristics and location(s) from which the user or user agent can choose the one most appropriate. The entity format is specified by the media type given in the Content-Type header field. The origin server MUST create the resource before returning the 201 status code. If the action cannot be carried out immediately, the server SHOULD respond with 202 (Accepted) response instead.


    我希望这有助于解释基本原理。我的(天真的?)理解是这个基本原理在 Web 框架中被广泛接受。从历史上看,我怀疑 Rails 是许多 REST 和面向资源的架构的狂热支持者的狂热实现基础(新词警告!)。

    关于ruby-on-rails-3 - Rails respond_with——为什么 POST 返回的是 URL 而不是数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11108844/

    相关文章:

    ruby-on-rails - 包含组和计数的 Rails 查询必须包含零

    mysql - Rails 的 schema.rb 总是显示所有索引吗?

    javascript - JSON 解析不适​​用于 ng-repeat

    javascript - 解析不带引号的 JSON 字符串

    http - 使用 HEAD 请求揭示 protected 资源的存在是否是 RESTful?

    html - 发布 html 表单数据重定向

    ruby-on-rails - 嵌套路由和 form_for 以及使用 has_one 和 belongs_to 的模型

    ruby-on-rails - Rails ActionMailer 附件留空正文

    java - 接口(interface)和@RequestBody

    java - SpringBootTest给出404错误,但curl成功