Ruby On Rails用户模型RSpec测试:密码确认验证失效
Hey there! It makes total sense to roll your own authentication system to really grok Ruby on Rails—great choice. Let's figure out why that validate_confirmation_of(:password) RSpec test is giving you trouble.
First, Check the Basics: Virtual Attributes
Rails' built-in validates_confirmation_of relies on a virtual attribute called password_confirmation (it doesn't live in your database). If your User model doesn't expose this attribute, the validation can't do its job.
Add this to your app/models/user.rb:
attr_accessor :password, :password_confirmation
This lets Rails read and write these temporary attributes (since you're not using has_secure_password which sets these up automatically).
Fix the Validation Setup
Make sure your model has the full set of password-related validations. Here's what that should look like:
class User < ApplicationRecord attr_accessor :password, :password_confirmation # Require both password and confirmation to be present validates :password, presence: true validates :password_confirmation, presence: true # Ensure password matches confirmation validates :password, confirmation: true # Your custom password encryption logic runs before saving before_save :encrypt_password private def encrypt_password # Replace this with your preferred encryption (e.g., SHA256, bcrypt if you want to use it without has_secure_password) self.password_digest = Digest::SHA256.hexdigest(password) end end
Adjust Your RSpec Tests
If you're using Shoulda Matchers, double-check they're properly configured in your rails_helper.rb (you'll need the shoulda-matchers gem in your Gemfile):
Shoulda::Matchers.configure do |config| config.integrate do |with| with.test_framework :rspec with.library :rails end end
Then, refine your test cases to cover both valid and invalid scenarios (this makes debugging easier):
require 'rails_helper' RSpec.describe User, type: :model do describe "password validations" do context "when password and confirmation don't match" do it "is not valid" do user = User.new( email: "test@example.com", # Add other required fields here password: "my_secure_password", password_confirmation: "wrong_password" ) expect(user).not_to be_valid expect(user.errors[:password_confirmation]).to include("doesn't match Password") end end context "when password and confirmation match" do it "is valid" do user = User.new( email: "test@example.com", password: "my_secure_password", password_confirmation: "my_secure_password" ) expect(user).to be_valid end end # Shoulda matcher tests should work now if the above is set up it { should validate_presence_of(:password) } it { should validate_presence_of(:password_confirmation) } it { should validate_confirmation_of(:password) } end end
Common Pitfalls to Avoid
- Missing virtual attributes: Without
attr_accessor :password_confirmation, Rails can't access the value you set in tests, so the validation will fail silently or throw an error. - Forgetting presence validations: If you don't require
password_confirmationto be present, the confirmation check won't run when the field is empty. - Outdated Shoulda Matchers: Make sure you're using a version of
shoulda-matcherscompatible with your Rails version (check the gem's docs if you're unsure).
Rolling your own auth is a fantastic way to learn the ins and outs of Rails—keep at it!
内容的提问来源于stack exchange,提问作者Smugller

