Ruby on rails 密码验证在两种相反的情况下失败
我正在学习MichaelHartl的RubyonRails教程,产生了一个有趣的难题。我会做错事的,所以我需要你帮我找出问题所在 问题围绕着Ruby on rails 密码验证在两种相反的情况下失败,ruby-on-rails,integration-testing,bcrypt,railstutorial.org,ruby-on-rails-5,Ruby On Rails,Integration Testing,Bcrypt,Railstutorial.org,Ruby On Rails 5,我正在学习MichaelHartl的RubyonRails教程,产生了一个有趣的难题。我会做错事的,所以我需要你帮我找出问题所在 问题围绕着用户模型中密码属性的验证。该属性的初始验证为: validates :password, presence: true, confirmation: true, length: { minimum: 6 } 这需要密码的最小长度,并且设计用于满足新用户创建
用户
模型中密码属性的验证。该属性的初始验证为:
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
因此,我们检查password字段不能包含空格或nil条目。有了当前的验证,这些测试就通过了。一切都很好
我已经发展到允许用户编辑他们的个人资料。这允许用户更改其姓名、电子邮件地址和密码/确认(如果他们选择)。为了允许用户在不想更改密码的情况下不更改密码,在模型的password属性中添加了附加验证,添加allow\u 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
这使用户只需编辑自己的姓名和电子邮件,并且通过将两个密码字段留空,无需更改或重新输入自己的密码。这会导致长时间通过测试失败,如上所述,例如:
test "password must not be blank or made up of spaces" do
@user.password = @user.password_confirmation = " "
assert_not @user.valid?
end
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
测试失败,因为用户已验证。稍有不同的测试,即测试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
,则此测试失败(上面粘贴了完整测试):
发送空白<代码>密码< /代码>和<代码>密码>确认>代码>测试失败,因为它不允许是空白的。
在验证中添加
allow\u 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\u blank:true
通常会绕过此测试或验证。任何空格数的password
都会被接受,这与模型中的验证不符。这怎么可能
任何关于如何更好地测试的想法(除了使用Rspec!)。我向您的渊博知识致敬
蒂亚
[编辑]
下面注释中建议的更改使我的测试套件变为绿色。这是因为套件不充分。为了测试不成功的集成,建议的代码一次性测试了多个场景,例如:
test "password must not be blank or made up of spaces" do
@user.password = @user.password_confirmation = " "
assert_not @user.valid?
end
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\u select
给出正确的结果。我没有。错误应该是空名称、无效电子邮件格式、密码太短、pwd和确认不匹配。短密码错误没有显示
我决定再进行两次测试,以证明密码长度和存在性验证失败。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
如果更改了密码,则应应用验证规则,即密码不应为空且必须具有最小长度。无论是在教程建议的代码中,还是在使用on::create
和on::edit
修改后的代码中,都没有出现这种情况。我发现了这一点,所以我在ca发布了这篇文章其他人也遇到了类似的问题
我修改了验证,将:update
操作包括在用户上,而不仅仅是:edit
。这包括了保存到数据库的操作,并捕获了简短的密码更新验证,但仍然允许使用空格构成的密码
稍微检查一下,我发现使用allow\u blank:true
允许nil
和由空格组成的字符串。这里的场景希望nil
密码是可接受的,但不是空密码。另一种验证allow\u 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
扩展的测试套件现在都是绿色的。
考虑这个问题的答案。在这个问题中有一些可替代的实现,@ MistelCar。同时,OP还提出了一个问题,即通过添加<代码> AuthyBL,将现有的最小长度和非空白的验证重写。ank:true
在代码中的某一点上,BCrypt
应该为新用户捕获非空白。事实上,update
操作并没有像新用户那样绕过验证(应该!)已遵守验证规则并拥有已验证的pwd。那么,此添加操作如何允许创建与验证规则相反的新用户?您只需在::create
上指定语句。然后创建另一个没有allow\u b的验证