0

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

我必须安装protected_attributesgem。我更喜欢使用这个 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 

这是我的文件。

用户.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
4

2 回答 2

1

这是 Rails 4 中的一个奇怪问题,由于某种原因,您无法在该上下文中为密码分配空白值。Rails 4.0RC1 版本的教程示例应用程序中的代码为 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

我已经在 Rails GitHub 存储库上提交了一个问题,希望能解决这个问题。

于 2013-05-30T02:05:41.483 回答
0

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

此外, has_secure_password 应该已经validates :password_confirmation, presence: true为您完成了,因此您应该从模型中删除该行。

于 2013-05-29T04:23:26.350 回答