Search code examples
ruby-on-railsbcryptminitest

Password can't be blank, bcrypt on user minitest, rails 6


When I try to validate my User model which uses bcrypt and has_secure_password in Rails 6, my valid user fixture validation results in an error.

The schema portion:

  create_table "users", force: :cascade do |t|
    t.string "first_name"
    t.string "last_name"
    t.string "email"
    t.string "password"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.string "password_digest"
  end

The model:

class User < ApplicationRecord
    has_many :organizations
    has_many :posts
    has_many :messages
    has_secure_password

    validates :first_name, presence: true 
    validates :last_name, presence: true
    VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
    validates :email, presence: true, format: { with: VALID_EMAIL_REGEX }, uniqueness: { case_sensitive: false }
    validates :password, presence: true, length: { minimum: 6 }

end

The fixture:

valid_user:
  id: 4
  first_name: A
  last_name: User
  email: [email protected]
  password_digest: <%= BCrypt::Password.create('password') %>

The test:

test 'valid user' do
  users(:valid_user).save!
  assert users(:valid_user).valid?
end

The error:

ERROR["test_valid_user", #<Minitest::Reporters::Suite:0x00007f8dac077ce0 @name="UserTest">, 1.0667385000000422]
 test_valid_user#UserTest (1.07s)
ActiveRecord::RecordInvalid:         ActiveRecord::RecordInvalid: Validation failed: Password can't be blank, Password is too short (minimum is 6 characters)
            test/models/user_test.rb:18:in `block in <class:UserTest>'

I added the bang to see why it wasn't valid, I'm setting a password that shouldn't be too short nor be blank. Whether I add a password fixture attribute and manually set it to "password", or try the digest, neither appear to work.

Thanks for your help!


Solution

  • Managed to resolve this with partial help from the following questions after getting the above suggestions, as well as reading further on has_secure_password. Thanks Schwern and Mshka!

    My last fixture validation needed to be updated to:

    validates :password, length: { minimum: 6 }, allow_nil: true
    

    To enable validation of password length yet allow for blank password, as has_secure_password already handles password validation/existence once set, so double-checking nil was unnecessary/didn't account for its own password handling validations.

    I updated my test to:

    test 'valid user' do
      assert users(:valid_user).valid?
      assert_instance_of User, users(:valid_user).authenticate("password")
    end
    

    Which validates the fixture and then ensures that the authentication returns a User (is successful).