在两种相反的情况下密码验证失败
Password validation fails in two opposed scenarios
我正在学习 Michael Hartl 在 Rails 教程中的 Ruby,并且遇到了一个有趣的难题。我会做错事,所以我需要你的帮助来找到问题所在。
问题围绕 User
模型中密码 属性 的验证。此 属性 的初始验证是:
validates :password, presence: true,
confirmation: true,
length: { minimum: 6 }
这需要密码的最短长度,旨在满足新用户创建实例的情况。
我在本书的指导下创建了以下测试(我希望我使用过 Rspec!)。这些测试检查验证是否有效:
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
因此,我们正在检查密码字段不能包含 space 或 nil 条目。通过当前的验证,这些测试通过了。一切顺利。
我已经允许用户编辑他们的个人资料。这使用户能够更改他们的姓名、电子邮件地址和 password/confirmation(如果他们愿意)。为了允许用户 not 在他们不想的情况下更改他们的密码,额外的验证被添加到模型的密码 属性,添加 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
。如上所述,这会在长时间通过的测试中抛出 FAIL,例如:
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 empty/nil" do
@user.password = @user.password_confirmation = ""
assert_not @user.valid?
end
因此密码 “”
被捕获,但密码 “ “
可以正常创建新用户或编辑现有用户。
将 allow_blank: true
添加到密码的用户模型验证似乎是造成这种情况的原因。因此,我陷入了两次失败的测试之间。如果我省略 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
发送空白 password
和 password_confirmation
测试失败,因为它不允许为空白。
在验证中添加 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
此失败允许使用由 space 组成的密码创建用户。不允许使用 nil
密码,即完全没有字符。该测试有效。
这让我不得不做出决定,如果用户编辑他们的个人资料,他们必须 change/repeat 他们的两个密码字段,或者允许用户可以使用包含以下内容的密码注册的场景一个 space 或多个 space,因为此测试不会抛出预期的失败消息:
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
的添加通常会绕过此测试或验证。接受任意数量的 space 的 password
,这违反了模型中的验证。这怎么可能?
任何关于如何更好地测试的想法(除了使用 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
给出正确的结果。我没有。错误应该是空白名称、无效的电子邮件格式、密码太短、密码和确认不匹配。短密码错误未显示。
我决定再抽出两个测试来证明密码长度和存在性验证失败。 allow_blank
的要点是在编辑用户配置文件时允许密码和确认字段中有 nothing 这样就不必每次用户都输入密码配置文件已编辑。这些测试是:
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
如果密码 已更改,则应应用验证规则,即密码不应为空且必须有最小长度。这不是教程书中建议的代码或使用 on: :create
和 on: :edit
的修改代码中发生的事情。
我弄明白了,所以我在这里发帖,以防其他人遇到类似问题。
我修改了验证以包括对 User
的 :update
操作,而不仅仅是 :edit
。这涵盖了保存到数据库的操作并捕获了简短的密码更新验证,但仍然允许由空格组成的密码。
对 documentation 的一些检查表明,使用 allow_blank: true
允许 nil
和由空格组成的字符串。这里的场景希望 nil
密码可以接受,但不能是空白密码。 allow_nil: true
的替代验证更适合这里的场景。
上面的更新代码看起来像 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
扩展测试套件现在全部为绿色。
我正在学习 Michael Hartl 在 Rails 教程中的 Ruby,并且遇到了一个有趣的难题。我会做错事,所以我需要你的帮助来找到问题所在。
问题围绕 User
模型中密码 属性 的验证。此 属性 的初始验证是:
validates :password, presence: true,
confirmation: true,
length: { minimum: 6 }
这需要密码的最短长度,旨在满足新用户创建实例的情况。
我在本书的指导下创建了以下测试(我希望我使用过 Rspec!)。这些测试检查验证是否有效:
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
因此,我们正在检查密码字段不能包含 space 或 nil 条目。通过当前的验证,这些测试通过了。一切顺利。
我已经允许用户编辑他们的个人资料。这使用户能够更改他们的姓名、电子邮件地址和 password/confirmation(如果他们愿意)。为了允许用户 not 在他们不想的情况下更改他们的密码,额外的验证被添加到模型的密码 属性,添加 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
。如上所述,这会在长时间通过的测试中抛出 FAIL,例如:
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 empty/nil" do
@user.password = @user.password_confirmation = ""
assert_not @user.valid?
end
因此密码 “”
被捕获,但密码 “ “
可以正常创建新用户或编辑现有用户。
将 allow_blank: true
添加到密码的用户模型验证似乎是造成这种情况的原因。因此,我陷入了两次失败的测试之间。如果我省略 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
发送空白 password
和 password_confirmation
测试失败,因为它不允许为空白。
在验证中添加 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
此失败允许使用由 space 组成的密码创建用户。不允许使用 nil
密码,即完全没有字符。该测试有效。
这让我不得不做出决定,如果用户编辑他们的个人资料,他们必须 change/repeat 他们的两个密码字段,或者允许用户可以使用包含以下内容的密码注册的场景一个 space 或多个 space,因为此测试不会抛出预期的失败消息:
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
的添加通常会绕过此测试或验证。接受任意数量的 space 的 password
,这违反了模型中的验证。这怎么可能?
任何关于如何更好地测试的想法(除了使用 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
给出正确的结果。我没有。错误应该是空白名称、无效的电子邮件格式、密码太短、密码和确认不匹配。短密码错误未显示。
我决定再抽出两个测试来证明密码长度和存在性验证失败。 allow_blank
的要点是在编辑用户配置文件时允许密码和确认字段中有 nothing 这样就不必每次用户都输入密码配置文件已编辑。这些测试是:
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
如果密码 已更改,则应应用验证规则,即密码不应为空且必须有最小长度。这不是教程书中建议的代码或使用 on: :create
和 on: :edit
的修改代码中发生的事情。
我弄明白了,所以我在这里发帖,以防其他人遇到类似问题。
我修改了验证以包括对 User
的 :update
操作,而不仅仅是 :edit
。这涵盖了保存到数据库的操作并捕获了简短的密码更新验证,但仍然允许由空格组成的密码。
对 documentation 的一些检查表明,使用 allow_blank: true
允许 nil
和由空格组成的字符串。这里的场景希望 nil
密码可以接受,但不能是空白密码。 allow_nil: true
的替代验证更适合这里的场景。
上面的更新代码看起来像 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
扩展测试套件现在全部为绿色。