1

我正在通過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 

因此,我們正在檢查密碼字段不能包含空格或零條目。通過當前的驗證,這些測試通過。一切都很好。

我已經發展到允許用戶編輯他們的個人資料。這使用戶可以更改他們的名字,電子郵件地址和密碼/確認,如果他們選擇。爲了讓用戶更改其密碼,如果他們不想要,額外的驗證被添加到模型中的密碼屬性,增加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 = "[email protected]" 
    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 

發送空白passwordpassword_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 

這失敗允許用戶用由空格的密碼來創建。 A 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繞過這個測試或一般的驗證。接受任何數量空間的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: "[email protected]", 
             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: "[email protected]", 
             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: "[email protected]", 
             password: " ", 
             password_confirmation: " " } } 
    assert_select 'div.alert', "The form contains 1 error." 
end 

如果密碼改變,那麼驗證規則應適用,即密碼不應該是空白,必須有一個最小長度。這不是教程本書建議的代碼或使用on: :createon: :edit的修改代碼。

+1

https://stackoverflow.com/questions/5123972/ruby-on-rails-password-validation考慮在這個問題上的答案。 – MisterCal

+0

在這個問題中有一些可選的實現@MisterCal。除了試圖找到一個可行的解決方案,OP還提出了一個問題,即現有的驗證最小長度和非空白度的方法是在'BCrypt'應該是代碼中的一個點添加'allow_blank:true'來重寫爲新用戶捕獲非空白。事實上,'update'行動並沒有繞過驗證,因爲新用戶將(應該)已經遵守驗證規則並且具有驗證的密碼。那麼,這個添加如何允許創建一個與驗證規則相反的新用戶呢? – OnlySteveH

+2

您只能指定'on::create'語句。然後創建另一個驗證,該驗證在::edit'上沒有'allow_blank'語句。 – MisterCal

回答

1

我想到了這一點,所以我在這裏張貼,以防其他人遇到類似的問題。

我修改了驗證,在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 

擴展的測試套件是現在所有的綠色。