Rails respond_with - 为什么POST返回URL而不是数据?

Tom*_*son 17 rest json respond-to ruby-on-rails-3

这是一个问题"为什么这样做",而不是"我如何使这项工作".

我的应用程序正在调用返回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 
Run Code Online (Sandbox Code Playgroud)

我的第三方API的包装器发出一个POST请求,返回正常,然后Rails返回500错误,记录如下:

NoMethodError (undefined method `{"response":{"message":"product 4e1712d9ec0f257c510013f8 selected"}}_url' for #<MyController> 
Run Code Online (Sandbox Code Playgroud)

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

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

如果我respond_with用旧式替换新的sytax

respond_to do |format|
  format.json { render :json => @products }  # note, no :location or :status options
end
Run Code Online (Sandbox Code Playgroud)

一切正常.这就是我所做的,所以我没有"如何"的问题,而是有一个"为什么"的问题.

Ryan Daigle关于引言的帖子解释了预期会发生什么.

我的问题是:为什么respond_with奢望什么数据以外,显然只是为了(HTTP状态?) POST.

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

Dav*_* J. 16

简介:Rails从HTTP和REST中获取其基本原理.

(感谢您更新的问题.现在我理解您的核心问题:"我并不是说它错了,只是想了解Rails实现的基本原理.")

现在来解释一下.Rails行为的基本原理源于拥抱HTTP和REST约定.

为了从您阅读的内容到我即将详细阐述的内容,我想提一下Ryan Daigle关于默认RESTful渲染的文章中的相关部分:

如果要求:html格式:

[删除了一些文字]

  • [在PUT或POST后没有验证错误]重定向到资源位置(即user_url)

(括号内的文字由我添加.)

如果请求了另一种格式,(即:xml或:json)

[删除了一些文字]

  • 如果是POST请求,则在资源上调用:to_format方法,然后将其发送回:created status和新创建的资源的:location.

让我用我的话来说明Rails认为是好的做法:

  • 对于人类内容(例如HTML),在POST或PUT之后,服务器应该告诉浏览器通过303重定向到新创建的资源.这是常见的做法 - 非常有用,因为用户希望查看其编辑产生的更新.

  • 对于机器内容(例如JSON,XML),在PUT之后,服务器应该只渲染201.在这种情况下,客户端使用API​​的程序可能会决定停在那里.(毕竟,客户端指定了请求并得到了201,所以所有人都很荣幸.)这就是使用201(成功)而不是303(重定向)的原因.如果客户端想要请求新创建的资源,它可以使用Location标头查找它 - 但不应强制重定向.

在任何一种情况下都要注意新创建的资源的位置是必需的.这就是为什么@products在上面的示例中需要同时包含数据和位置.

作为背景,我在201创建W3C页面上分享了一些内容:

10.2.2 201创建

请求已完成,并导致创建新资源.新创建的资源可以由响应实体中返回的URI引用,其中由Location头字段给出的资源的最具体URI.响应应该包括一个实体,其中包含资源特征和位置的列表,用户或用户代理可以从中选择最合适的资源特征和位置.实体格式由Content-Type头字段中给出的媒体类型指定.原始服务器必须在返回201状态代码之前创建资源.如果无法立即执行操作,服务器应该响应202(已接受)响应.

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

  • 对于人类内容,重定向还会强制浏览器执行 GET 请求来显示结果,这将阻止用户在刷新浏览器时重新发布其数据。 (2认同)