6

使用 rails 4 我在我的用户模型中使用has_secure_password,trick 说如果我不设置 :password_confirmation 它永远不会被触发但是为什么当我运行测试时我得到错误:密码确认不能为空,如下所示:

Failures:

1) User 
 Failure/Error: it { should be_valid }
   expected #<User id: nil, name: "joe", email: "joe@mail.com", created_at: nil, 
   updated_at: nil, password_digest: "$2a$04$mcRr/msgYQR3kBVc3kv/m.UotBJuJuSXZKMw
   /eHTvU87..."> to be valid, but got errors: Password confirmation can't be blank

我的测试文件看起来像:

require 'spec_helper'

describe User do

   before { @user = User.new(name: 'joe', email: 'joe@mail.com', password: 'foo') }

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

为什么我收到此错误,有解决方案吗?谢谢

4

3 回答 3

21

长话短说

has_secure_password validations: false # This is the key to the solution
validates :password, presence: true, length: { minimum: 6 } # Or an length you want

长篇大论

  1. 文档和源代码说:

    如果您不需要确认验证,只需不要为 password_confirmation 属性设置任何值,验证将不会被触发。

  2. 但他们也说:

    自动添加创建时密码存在验证、密码确认(使用 +password_confirmation+ 属性)。如果您希望关闭验证,请传递验证:false 作为参数。如果需要,您可以手动添加更多验证。

  3. 第 1 项不是完整的描述。我们需要关闭所有验证并添加我们自己的验证规则,以使这项工作如第 2 点所述。

我花了一些时间在这上面得到了一个教训:当你感到困惑时,找到源代码。这似乎是一种痛苦的方式或艰难的方式,但有时它是正确的方式。

于 2013-09-18T03:14:55.390 回答
5

将您的测试before行更改为:

before { @user = User.new(
  name: 'joe',
  email: 'joe@mail.com',
  password: 'foo',
  password_confirmation: 'foo')  #<== this line!
}

那应该解决它。

这是关于什么的:

您知道当您在几乎任何网站上创建新帐户时,他们会要求您输入密码并输入两次吗?就是这样。当您创建一个新用户时,has_secure_password需要两次密码以确保您没有输入错误。

如果password!= password_confirmation,它将引发异常并且不会创建用户。

同样,这仅用于用户创建。您无需在登录表单或其他任何内容中输入两个密码。 您不必将此字段添加到您的模型或数据库中。

如果您有一个用户创建表单,并且您不想拥有一个password_confirmation字段,那么您就不必这样做。你可以password_confirmation = password在你的控制器中设置,在你调用 save 之前。

但是对于用户创建password_confirmation 必须存在。

于 2013-07-31T00:41:22.493 回答
1

在我从 Rails 4.0.13 到 4.1 及更高版本获得此应用程序之前,我这样做是一种临时措施:

class User < ActiveRecord::Base
  has_secure_password
  # Tempfix until Rails 4.1 https://github.com/rails/rails/pull/11107#issuecomment-21850919
  raise "Get rid of this on Rails 4.1+" if Rails::VERSION::STRING != "4.0.13"
  before_validation { self.password_confirmation ||= password }
end
于 2015-02-28T18:12:03.653 回答