rails 4 has_secure_password render password confir

2020-06-04 10:19发布

with rails 4 i use has_secure_password in my user model , trick says that if i don't set the :password_confirmation it will never be triggered but why when i run the test i get error : Password confirmation can't be blank as the following :

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

my test file look like :

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

why i get this error, there is a solution for that ? thank's

3条回答
Animai°情兽
2楼-- · 2020-06-04 10:22

Long story short

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

The Long story

  1. The docs and the source code say:

    If you don’t need the confirmation validation, just don’t set any value to the password_confirmation attribute and the the validation will not be triggered.

  2. But they also say:

    Validations for presence of password on create, confirmation of password (using a +password_confirmation+ attribute) are automatically added. If you wish to turn off validations, pass validations: false as an argument. You can add more validations by hand if need be.

  3. Item #1 is not a complete description. We need to turn off all validation and add our own validation rules to make this work like as described in point #2.

I spent sometime on this and got a lesson: find the source code when you are confused. This seems to be a painful way or hard way, but sometime it's the right way.

查看更多
一夜七次
3楼-- · 2020-06-04 10:45

Change your test's before line to this:

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

That should fix it.

What this is about:

You know how when you create a new account on pretty much any website, they ask you to make up a password and enter it twice? That's what this is. When you create a new user, has_secure_password wants the password twice to make sure you didn't make a typo.

If password != password_confirmation, it will throw an exception and the user won't be created.

Again, this is only used on user creation. You don't need to enter two passwords in the login form or anything else. You don't have to add this field to your model or DB.

If you have a user creation form, and you don't want to have a password_confirmation field, then you don't have to. You can set password_confirmation = password in your controller, before you call save or whatever.

But for User creation, the password_confirmation must be present.

查看更多
Ridiculous、
4楼-- · 2020-06-04 10:45

I did this as a temporary measure until I get this app from Rails 4.0.13 to 4.1 and beyond:

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
查看更多
登录 后发表回答