为什么Rails默认创建为HTML格式的集合上的POST?

时间:2016-05-21 13:08:56

标签: ruby-on-rails rest devise

生成支架时,默认情况下new_resource_path会生成一个提交到resources_path的表单。

这在RESTful心态中是完全有道理的。

但是,鉴于生成的材料不将其用作REST资源,为什么要POST到收集路径?

成功创建资源后,Rails将重定向到创建的资源路径。发生任何错误时,Rails将呈现将显示错误的new模板(由脚手架生成)。

这似乎很好,除了在尝试创建资源时发生任何错误时,URL将更改为收集路径。这意味着如果用户尝试刷新页面,则不会看到创建表单。如果应用程序不允许列出此资源,则可能发生路由错误。如果应用程序使用任何类型的授权,并且当前用户没有列出内容所需的授权,则可能会看到禁止。

我认为Rails脚手架生成器是社区同意在其中执行基本CRUD的标准方法。那么,为什么会这样呢?

似乎通过保持纯粹的RESTful资源方法,我们正在打破用户体验。

要查看此示例,只需创建一个新的Rails应用程序,搭建一个新实体并尝试使用一些验证错误创建它。

$ rails new example
$ cd example
$ rails generate scaffold note text
# edit app/models/note.rb
  class Note < ApplicationRecord
   validates :text, length: { minimum: 10 }
  end
$ rails db:migrate
$ rails server
# go to localhost:3000/notes/new
# click 'Create Note'
# see the error
# hit browser's refresh button
# now you are listing notes, and not creating one

如果您认为“这不应该损害真正的应用程序”。我在编写验证测试时想出了这个。

我的应用程序正在使用Devise,但未通过此测试:

test 'new user should not be able to register with wrong password confirmation' do
  email = 'newuser@newdomain.com'
  password = 'little$secret'
  password_confirmation = 'big$secret'

  visit new_user_registration_path
  fill_in 'Email', with: email
  fill_in 'Password', with: password
  fill_in 'Password confirmation', with: password_confirmation

  assert_no_difference ->{ User.count } do
    click_on 'Sign up'
  end

  assert page.has_content?("Password confirmation doesn't match Password")
  # FAILS:
  assert_equal new_user_registration_path, current_path
end

这在现实生活中意味着什么:当用户尝试创建帐户时,提交无效表单,查看错误并点击刷新,因为资源不支持列表,所以它位于无效路径上(即/users )。

要使最后一个断言通过,我必须覆盖默认的Devise视图,将表单提交到/users/sign_up而不是/users,并添加新路由以便在create时调用对此URL进行POST。然后我意识到这将发生在遵循RESTful资源方法的任何控制器上,除非开发人员创建这个新路由并使用自定义URL来提交创建表单。

此外,“纯粹的RESTful资源方法”似乎并不那么纯粹。当您使用无效数据提交表单时,POST将导致200 OK呈现带有错误的HTML,而不是400 Bad Request。那么,为什么不将表单提交到表单中存在的相同URL?

我敢打赌,我错过了什么,但我无法理解。那么,我错过了什么?

2 个答案:

答案 0 :(得分:1)

  

但是,鉴于生成的材料不将其用作REST   资源,为什么POST到收集路径?   那么,为什么不将表单提交到表单中存在的相同URL?

因为rails惯例包含无状态。 create失败时看到的表单显示POST请求的结果。它并不意味着重复 - 或共享。

你可能有POST /notes/create并创建一个GET /notes/create路由,以便在刷新后显示表单 - 但从框架的角度来看这是一个好的设计吗?我会说不。

POST回到同一URL的表单可能会给用户带来糟糕的体验 - 比如点击后退按钮时的“确认表单提交”对话框。这实际上比您正在绘制的场景更糟糕,因为它可能会给用户带来意想不到的后果。

  

我认为Rails脚手架生成器是社区同意的   在其中进行基本CRUD的标准方法。

rails scaffold命令是一种快速原型制作工具。它们并不是作为“正确”做轨道的权威来源,也不是社区将它们视为上帝之道。

  

此外,“纯粹的RESTful资源方法”似乎并非如此   纯粹。

Rails社区不是很纯粹。如果它是非常务实的,并且旨在接受像REST这样的概念,但注重开发人员的便利性和“应该只是工作”。

  

当您提交包含无效数据的表单时,POST会   导致200 OK呈现带有错误的HTML,而不是400 Bad   请求。

这是实用主义,在当天使用4XX响应代码时,Internet Explorer会做各种恼人的事情。 200 OK保证客户端将呈现响应 - 尽管它在技术上是错误的。

答案 1 :(得分:-2)

  

这似乎很好,除了在尝试时发生任何错误   创建资源后,URL将更改为集合路径。这个   意味着如果用户尝试刷新页面,它将无法看到   创作形式。

我没有得到你:如果你刷新页面,它只会重新发布相同的参数,所以显示相同的表格有错误。我刚刚重新检查了一下。

  

如果应用程序不允许列出此资源,则路由   可能会发生错误。如果应用程序使用任何类型的   授权和当前用户没有必要的   授权列出内容,可能会看到禁止。

因此,例如,不允许用户查看帖子列表,但是可以创建新帖子吗?