代码之家  ›  专栏  ›  技术社区  ›  OnlySteveH

密码验证在两种相反的情况下失败

  •  1
  • OnlySteveH  · 技术社区  · 7 年前

    我正在学习Michael Hartl的Ruby on Rails教程,产生了一个有趣的难题。我会做错什么,所以我需要你的帮助来发现问题。

    该问题围绕着验证 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
    

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

    我已经允许用户编辑他们的个人资料。这使用户可以根据自己的选择更改其姓名、电子邮件地址和密码/确认。为了允许用户 如果他们不想更改密码,则会在模型的password属性中添加额外的验证,添加 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
    

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

    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
    

    所以密码为 “” “ “ 可以很好地创建新用户或编辑现有用户。

    正在添加 允许空白:true 对用户模型的密码验证似乎是造成这种情况的原因。所以,我被困在两次测试失败之间。如果我省略 允许空白: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_confirmation 测试失败,因为它不允许为空。

    正在添加 允许空白:true 在验证过程中,该测试失败:

    测试“密码不得为空或由空格组成”do
    @用户。密码=@用户。password_confirmation=“”
    assert\u not@用户。有效的
    终止
    

    此失败允许使用由空格组成的密码创建用户。A. 不允许使用密码,即不允许使用任何字符。该测试有效。

    这使得我必须在用户编辑其配置文件时必须更改/重复其两个密码字段之间做出决定,或者允许用户使用由一个或多个空格组成的密码注册,因为此测试不会抛出预期的失败消息:

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

    添加 允许空白:true 暗语 接受任意数量的空间,这不利于模型中的验证。这怎么可能?

    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 给出正确的结果。我没有。错误应该是空白的名字,无效的电子邮件格式,密码太短,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 .

    1 回复  |  直到 6 年前
        1
  •  1
  •   OnlySteveH    7 年前

    我发现了这一点,所以我在这里张贴,以防其他人遇到类似的问题。

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

    documentation 向我展示了使用 allow_blank: true 允许 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
    

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