为什么密码验证存在被忽略?

时间:2013-05-29 03:06:33

标签: ruby-on-rails ruby rspec

我正在关注Michael Hartl Ruby on Rails教程。我在第6.3节遇到了测试失败的问题。代码应验证空白密码,但如果我使用密码创建User对象,然后将密码字段更改为空白,valid?将返回true,根据测试规范,这不是预期的。我错过了什么吗?

我必须安装protected_attributes宝石。我更喜欢使用这个gem来遵循教程代码而不做任何修改。

正在运行bundle exec rspec spec

rspec ./spec/models/user_spec.rb:90 # User when password confirmation is nil 
rspec ./spec/models/user_spec.rb:80 # User when password is not present 

这是我的档案。

user.rb:

class User < ActiveRecord::Base
  attr_accessible :name, :email, :password, :password_confirmation
  has_secure_password

  before_save { |user| user.email = email.downcase }

  validates :name, presence: true, length: { maximum: 50 }
  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 }
  validates :password_confirmation, presence: true
end

user_spec.rb(只有失败的测试):

  describe "when password is not present" do
    before { @user.password = @user.password_confirmation = " " }
    it { should_not be_valid }
  end

  describe "when password confirmation is nil" do
    before { @user.password_confirmation = nil }
    it { should_not be_valid }
  end

以下是我在控制台中运行的一些测试:

max@top:~/prog/ruby/railstut$ rails c --sandbox
Loading development environment in sandbox (Rails 4.0.0.rc1)
Any modifications you make will be rolled back on exit
irb(main):001:0> # Should return true.
irb(main):002:0* User.new(name: "Example User", email: "user@example.com",
irb(main):003:1*                      password: "foobar", password_confirmation: "foobar").valid?
  User Exists (1.8ms)  SELECT 1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER('user@example.com') LIMIT 1
=> true
irb(main):004:0> 
irb(main):005:0* # Should return false.
irb(main):006:0* User.new(name: "Example User", email: "user@example.com",
irb(main):007:1*                      password: "", password_confirmation: "foobar").valid?
  User Exists (0.8ms)  SELECT 1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER('user@example.com') LIMIT 1
=> false
irb(main):008:0> 
irb(main):009:0* # Oops. Expecting false.
irb(main):010:0* user = User.new(name: "Example User", email: "user@example.com",
irb(main):011:1*                      password: "foobar", password_confirmation: "foobar")
=> #<User id: nil, name: "Example User", email: "user@example.com", created_at: nil, updated_at: nil, password_digest: "$2a$10$ygkdtuJYF89ysbD86ZcO9ugiQZ0/FxOKvj87zEegJq.f...">
irb(main):012:0> 
irb(main):013:0* user.password = ""
=> ""
irb(main):014:0> 
irb(main):015:0* user.valid?
  User Exists (0.5ms)  SELECT 1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER('user@example.com') LIMIT 1
=> true

2 个答案:

答案 0 :(得分:1)

这是Rails 4中的一个奇怪问题,由于某种原因,您无法在该上下文中为密码分配空白值。 Rails 4.0RC1 version of the tutorialsample app中的代码为Rails 4提供了解决方法。基本上,您必须使用哈希重新创建对象,如

describe "when password is not present" do
  before do
    @user = User.new(name: "Example User", email: "user@example.com",
                     password: " ", password_confirmation: " ")
  end
  it { should_not be_valid }
end

我已经提交issue on the Rails GitHub repository希望解决此问题。

答案 1 :(得分:0)

我认为您的validates :password, presence: true验证可能会与Rails 4中has_secure_password添加的验证冲突。请参阅Ryan B的回答here

另外,has_secure_password应该已为您validates :password_confirmation, presence: true执行,因此您应该从模型中删除该行。