在两个相反的情况下密码验证失败 [英] Password validation fails in two opposed scenarios

查看:99
本文介绍了在两个相反的情况下密码验证失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在研究Michael Hartl编写的Ruby on Rails教程,并产生了一个有趣的难题.我做错了什么,所以我需要您的帮助才能找到问题.

I am working through the Ruby on Rails Tutorial by Michael Hartl and have generated an interesting dilemma. I will have done something wrong, so I need your help finding the issue.

问题涉及User模型中密码属性的验证.此属性的初始验证为:

The issue surrounds the validation of a password property within a User model. The initial validation of this property was:

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

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

This requires a minimum length of the password and is designed to satisfy the situation where a new user creates their instance.

在本书的指导下,我创建了以下测试(并且我希望我使用过Rspec!).这些测试检查验证是否有效:

I have created the following tests (and I wish I had used Rspec!) guided by the book. These tests check that the validations work:

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

因此,我们正在检查密码字段中不能包含空格或nil条目.通过当前的验证,这些测试通过了.一切都很好.

So, we’re checking that the password field cannot contain either a space, or a nil entry. With the current validations, these tests pass. All is well.

我已经开始允许用户编辑其个人资料.这使用户可以根据需要更改其名称,电子邮件地址和密码/确认.为了允许用户更改其密码(如果他们不想这样做),将附加验证添加到模型的password属性中,并添加allow_blank: true,例如:

I have progressed to allowing a user to edit their profile. This enables the user to change their name, email address and password/confirmation if they choose. In order to allow a user not to change their password if they don’t want to, additional validation is added to the password property of the model, adding allow_blank: true such as:

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

因此,如果用户不想更改其个人资料,则现在可以在编辑个人资料时将两个密码字段保留为空白.这可以满足测试要求:

So, the user can now leave the two password fields blank when they edit their profile if they don’t want to change their profile. This satisfies the test:

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.如上所述,这会导致长时间通过测试失败,例如:

This enables a user to edit just their name & email and, by leaving their two password fields blank, there’s no need to change, or re-enter, their password. This throws a FAIL on a long passing test, as above, such as:

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

由于用户已通过验证,因此测试失败.稍有不同的测试通过了nil而不是空白的测试,通过了:

The test fails because the user is validated. The slightly different test, which tests for nil, not blank, passes:

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

因此会捕获到密码,但是密码 可以很好地用于创建新用户或编辑现有用户.

So a password of "" is caught but a password of " " works fine for creating a new user or editing an existing user.

allow_blank: true添加到密码的用户模型验证中似乎是导致此问题的原因.因此,我陷入了两次失败的测试之间.如果我省略allow_blank: true,则此测试将失败(上面粘贴了完整测试):

Adding allow_blank: true to the user model validation of password seems to have caused this. So, I am stuck between two tests failing. If I omit allow_blank: true, this test fails (full test pasted above):

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不能通过测试,因为不允许空白.

Sending the blank password and password_confirmation fails the test as it isn’t allowed to be blank.

在验证中添加allow_blank: true会使测试失败:

Adding allow_blank: true within the validation fails this test:

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

此失败允许使用包含空格的密码来创建用户.不允许使用nil密码,即完全没有字符.该测试有效.

This fail allows a user to be created with a password consisting of spaces. A nil password, i.e. no characters at all, is not allowed. That test works.

这使我处于以下位置:我必须决定用户是否必须更改/重复他们的两个密码字段(如果他们编辑其个人资料),或者允许用户使用由一个空格组成的密码进行注册的情况,或很多空格,因为此测试不会引发预期的失败消息:

This leaves me in the position where I must decide between a user having to change/repeat their two password fields if they edit their profile, OR, allowing a scenario where a user can sign up with a password consisting of one space, or many spaces, as this test doesn’t throw the expected failure message:

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通常会绕过该测试或验证.接受任意数量的空格的password,这与模型中的验证相反.那怎么可能?

The addition of allow_blank: true bypasses this test or the validation generally. A password of any number of spaces is accepted which is against the validation in the model. How is that possible?

任何人都在思考如何进行更好的测试(除了使用Rspec!).我向你更多的知识鞠躬.

Any thoughts how to test better (apart from using Rspec!). I bow to your greater knowledge.

TIA.

以下注释中建议的更改使我的测试套件变成绿色.这是由于套房不足.为了测试失败的集成,建议的代码一次性测试了多个方案,例如:

The suggested changes in the comments below made my test suite green. This was due to the suite being inadequate. To test the unsuccessful integration, the suggested code tested multiple scenarios in one go, such as:

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提供正确的结果.我没有错误应为空白名称,无效的电子邮件格式,密码太短,pwd&确认不符.短密码错误未显示.

The key part here is getting the number of expected errors correct so that assert_select gives the right result. I didn't. The errors should be blank name, invalid email format, password too short, pwd & confirmation don't match. The error for short password isn't showing.

我决定再进行两次测试,以证明密码长度和状态验证失败. allow_blank的要点是允许密码&确认字段在编辑用户个人资料时不包含任何内容,因此每次编辑用户个人资料时都不必输入密码.这些测试是:

I decided to pull out two more tests to demonstrate the failure of the validations of password length and presence. The point of allow_blank is to allow the password & confirmation fields to have nothing in them when editing the user profile so it isn't compulsory to enter the password every time the user profile is edited. These tests are:

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: :createon: :edit进行了修改的代码中,都没有发生这种情况.

If the password is changed, then the validation rules should apply, i.e. the password should not be blank and must have a minimum length. That's not what's happening here either in the code the Tutorial book suggests or the amended code using on: :create and on: :edit.

推荐答案

我知道了这一点,因此请在此处发布,以防其他人遇到类似问题.

I figured this out so am posting here in case others come across a similar problem.

我修改了验证,以包括对User:update动作,而不仅仅是:edit.这涵盖了保存到数据库的操作,并捕获了简短的密码更新验证,但仍然允许密码由空格组成.

I amended the validations to include the :update action on the User, rather than just :edit. This covered the action of saving to the database and caught the short password update validations but still allowed passwords made of spaces.

仔细检查文档可以发现,使用allow_blank: true 允许 nil和由空格组成的字符串.这里的情况希望nil密码可以接受,但不能空白. allow_nil: true的替代验证更适合此处的情况.

A bit of checking the documentation showed me that using allow_blank: true allows nil and strings made up of spaces. The scenario here wants a nil password to be acceptable, but not a blank one. The alternative validation of allow_nil: true is more appropriate to the scenario here.

上面更新的代码在User.rb中如下所示:

The updated code from above looks like, in 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

扩展的测试套件现在全为绿色.

The extended test suite is now all green.

这篇关于在两个相反的情况下密码验证失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆