为什么Rails默认创建为HTML形式的POST on集合



生成脚手架时,默认情况下,new_resource_path会生成一个将提交给resources_path的表单。

这在RESTful心态中是完全有意义的。

但是,既然生成的材料没有将其用作REST资源,为什么它要POST到集合路径?

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

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

我认为Rails scaffold生成器是社区同意的在其中执行基本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,并在对该URL进行POST时添加一个新的路由来调用create。然后我意识到,除非开发人员创建这个新路由并使用自定义URL提交创建表单,否则任何遵循RESTful Resource方法的控制器都会发生这种情况。

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

我打赌我错过了什么,但我想不通。那么,我错过了什么?

但是,假设生成的材料不将其用作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保证客户端将提供响应——尽管它在技术上是错误的。

这似乎很好,只是当尝试创建资源时,URL将更改为集合路径。这意味着如果用户尝试刷新页面,它将看不到创建表单。

我不明白:如果你刷新页面,它只会重新POST相同的参数,因此显示相同的表单并出现错误。我只是重新检查了一下。

如果应用程序不允许列出此资源,则路由可能会发生错误。如果应用程序使用任何类型的授权,而当前用户没有所需的授权列出东西,可能会被禁止。

因此,例如,不允许用户查看帖子列表,但允许用户创建一个新帖子?

最新更新