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!
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).