密码validation在两个相反的情况下失败

我正在研究Michael Hartl的Ruby on Rails教程,并产生了一个有趣的困境。 我会做错事,所以我需要你帮忙找到问题。

该问题围绕User模型中的密码属性validation。 该属性的初始validation是:

 validates :password, presence: true, confirmation: true, length: { minimum: 6 } 

这需要最小长度的密码,旨在满足新用户创建其实例的情况。

我已经创建了以下测试(我希望我使用过Rspec!)。 这些测试检查validation是否有效:

 test "password must not be blank or made up of spaces" do @user.password = @user.password_confirmation = " " assert_not @user.valid? end test "password must not be empty/nil" do @user.password = @user.password_confirmation = "" assert_not @user.valid? end 

因此,我们检查密码字段不能包含空格或零条目。 通过当前的validation,这些测试通过了。 一切都很好。

我已经发展到允许用户编辑他们的个人资料。 这使用户可以选择更改其姓名,电子邮件地址和密码/确认。 为了让用户不想更改密码,可以在模型的密码属性中添加额外的validation,添加allow_blank: true例如:

 validates :password, presence: true, confirmation: true, length: { minimum: 6 }, allow_blank: true # added this! 

因此,如果用户不想更改其个人资料,则他们可以在编辑个人资料时将这两个密码字段留空。 这满足了测试:

 test "successful edit" do log_in_as @user get edit_user_path(@user) assert_template 'users/edit' name = "Foo Bar" email = "foo@valid.co.uk" patch user_path(@user), params: { user: { name: name, email: email, password: "", password_confirmation: "" } } assert_not flash.empty? assert_redirected_to @user @user.reload assert_equal @user.name, name assert_equal @user.email, email end 

这使用户只需编辑他们的姓名和电子邮件,并将两个密码字段留空,无需更改或重新输入password 。 如上所述,这会导致长时间通过测试失败,例如:

 test "password must not be blank or made up of spaces" do @user.password = @user.password_confirmation = " " assert_not @user.valid? end 

测试失败,因为用户已经过validation。 稍微不同的测试,测试nil ,而不是空白,通过:

 test "password must not be empty/nil" do @user.password = @user.password_confirmation = "" assert_not @user.valid? end 

因此,捕获密码“” ,但密码“ “适用于创建新用户或编辑现有用户。

添加allow_blank: true到用户模型validation密码似乎已经导致了这一点。 所以,我被困在两次测试失败之间。 如果我省略allow_blank: true ,则此测试失败(上面粘贴的完整测试):

 test "successful edit" do . . patch user_path(@user), params: { user: { name: name, email: email, password: "", password_confirmation: "" } } . assert_equal @user.name, name assert_equal @user.email, email end 

发送空passwordpassword_confirmation未通过测试,因为它不允许为空。

在validation中添加allow_blank: true导致此测试失败:

 test "password must not be blank or made up of spaces" do @user.password = @user.password_confirmation = " " assert_not @user.valid? end 

此失败允许使用由空格组成的密码创建用户。 不允许使用nil密码,即根本没有字符。 那个测试有效。

这使我处于必须在用户必须更改/重复两个密码字段(如果他们编辑其配置文件)之间做出决定的位置,或者允许用户可以使用由一个空格或多个空格组成的密码进行注册的场景,因为此测试不会抛出预期的失败消息:

 test "password must not be blank or made up of spaces" do @user.password = @user.password_confirmation = " " assert_not @user.valid? end 

allow_blank: true的添加通常会绕过此测试或validation。 接受任意数量空格的password ,这违反了模型中的validation。 怎么可能?

任何想法如何更好地测试(除了使用Rspec!)。 我向你们提供更多的知识。

TIA。

[编辑]

以下评论中的建议更改使我的测试套件变为绿色。 这是由于套房不足。 为了测试不成功的集成,建议的代码一次性测试了多个场景,例如:

 test "unsuccessful edit with multiple errors" do log_in_as @user get edit_user_path(@user) assert_template 'users/edit' patch user_path(@user), params: { user: { name: "", email: "foo@invalid", password: "foo", password_confirmation: "bar" } } assert_template 'users/edit' assert_select 'div.alert', "The form contains 3 errors." end 

这里的关键部分是使预期错误的数量正确,以便assert_select给出正确的结果。 我没有。 错误应为空白名称,电子邮件格式无效,密码太短,密码和确认不匹配。 短密码错误未显示。

我决定再抽出两个测试来certificate密码长度和存在的validation失败。 allow_blank是在编辑用户配置文件时允许密码和确认字段中没有任何内容 ,因此每次编辑用户配置文件时都不必输入密码。 这些测试是:

 test "unsuccessful edit with short password" do log_in_as @user get edit_user_path(@user) assert_template 'users/edit' patch user_path(@user), params: { user: { name: @user.name, email: "foo@valid.com", password: "foo", password_confirmation: "foo" } } assert_select 'div.alert', "The form contains 1 error." end test "unsuccessful edit with blank (spaces) password" do log_in_as @user get edit_user_path(@user) assert_template 'users/edit' patch user_path(@user), params: { user: { name: @user.name, email: "foo@valid.com", password: " ", password_confirmation: " " } } assert_select 'div.alert', "The form contains 1 error." end 

如果密码更改,则应应用validation规则,即密码不应为空白且必须具有最小长度。 这不是这里发生的事情,无论是在教程书中建议的代码中,还是在修改后的代码上使用::: on: :create on: :edit

我想出了这个,所以我发布在这里以防其他人遇到类似的问题。

我修改了validation以包括:updateUser :update操作,而不仅仅是:edit 。 这包括保存到数据库的操作,并捕获短密码更新validation但仍允许使用空格密码。

检查文档有点让我看到使用allow_blank: true 允许 nil和由空格组成的字符串。 这里的场景想要一个nil密码是可以接受的,但不是空白密码。 allow_nil: true的替代validation更适合此处的场景。

User.rb ,上面的更新代码如下User.rb

 validates :password, presence: true, length: { minimum: 6 }, allow_nil: true, on: [:edit, :update] validates :password, presence: true, confirmation: true, length: { minimum: 6 }, on: :create 

扩展的测试套件现在都是绿色的。