user2253215
user2253215

Reputation: 97

Password digest missing on new record

I think a lot of people have asked this question, but unfortunately I didn't understand the answers they were given. Basically, I need you guys to just say, "AND THIS IS THE CODE YOU NEED HERE PASTE," and then explain it to me because, frankly, I don't get it.

Okay, so here's the issue. I'm running a test for my user model, and this is what happens:

1) User return value of authenticate method with valid password 
 Failure/Error: before { @user.save }
 RuntimeError:
   Password digest missing on new record
 # ./spec/models/user_spec.rb:61:in `block (3 levels) in <top (required)>'

2) User return value of authenticate method with invalid password 
 Failure/Error: before { @user.save }
 RuntimeError:
   Password digest missing on new record
 # ./spec/models/user_spec.rb:61:in `block (3 levels) in <top (required)>'

3) User return value of authenticate method with invalid password 
 Failure/Error: before { @user.save }
 RuntimeError:
   Password digest missing on new record
 # ./spec/models/user_spec.rb:61:in `block (3 levels) in <top (required)>'

Now for my code. Here's my rspec:

require 'spec_helper'

describe User do
before do
    @user = User.new(first: "Example", last: "Example", email: "[email protected]", password: "foobar", password_confirmation: "foobar")
end

subject { @user }

it { should respond_to(:first) }
it { should respond_to(:last) }
it { should respond_to(:email) }  
it { should respond_to(:password_digest) }
it { should respond_to(:password) } 
it { should respond_to(:password_confirmation) }
it { should respond_to(:authenticate) }

it { should be_valid }

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

describe "when name is too long" do
    before { @user.first = "a" * 51 }
    it { should_not be_valid }
end

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

describe "when name is too long" do
    before { @user.last = "a" * 51 }
    it { should_not be_valid }
end

describe "when email format is invalid" do
    it "should be invalid" do
     addresses = %w[user@foo,com user_at_foo.org [email protected]@bar_baz.com foo@bar+baz.com]
    addresses.each do |invalid_address|
    @user.email = invalid_address
    expect(@user).not_to be_valid
  end
end
end

describe "when email format is valid" do
    it "should be valid" do
    addresses = %w[[email protected]]
    addresses.each do |valid_address|
    @user.email = valid_address
    expect(@user).to be_valid
  end
end
end

describe "return value of authenticate method" do
  before { @user.save }
  let(:found_user) { User.find_by(email: @user.email) }

  describe "with valid password" do
    it { should eq found_user.authenticate(@user.password) }
  end

  describe "with invalid password" do
    let(:user_for_invalid_password) { found_user.authenticate("invalid") }

    it { should_not eq user_for_invalid_password }
    specify { expect(user_for_invalid_password).to be_false }
  end
end

end

And here is my user model:

class User < ActiveRecord::Base
attr_accessible :first, :last, :email, :password, :password_confirmation
attr_accessor :password, :password_confirmation
has_secure_password

before_save { self.email = email.downcase }
validates :first, :last, presence: true, length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+@[andover]+\.[edu]+\z/i
validates :email, presence:   true,
                format:     { with: VALID_EMAIL_REGEX },
                uniqueness: { case_sensitive: false }
validates :password, length: { minimum: 6 }
end

And here is my gemfile:

source 'https://rubygems.org'
ruby '2.0.0'
#ruby-gemset=railstutorial_rails_4_0

gem 'rails', '4.0.2'
gem 'bootstrap-sass', '2.3.2.0'
gem 'bcrypt-ruby', '~> 3.1.2'
gem "protected_attributes", :github => "rails/protected_attributes"

group :development, :test do
  gem 'sqlite3', '1.3.8'
  gem 'rspec-rails', '2.13.1'
end

group :test do
  gem 'selenium-webdriver', '2.35.1'
  gem 'capybara', '2.1.0'
end

gem 'sass-rails', '4.0.1'
gem 'uglifier', '2.1.1'
gem 'coffee-rails', '4.0.1'
gem 'jquery-rails', '3.0.4'
gem 'turbolinks', '1.1.1'
gem 'jbuilder', '1.0.2'

group :doc do
  gem 'sdoc', '0.3.20', require: false
end

group :production do
  gem 'pg', '0.15.1'
  gem 'rails_12factor', '0.0.2'
end

I'm not going to waste more space by posting my schema, but I do want to say that I put this in the schema: t.string "password_digest". I know that was a problem for some people, since they left it off.

Your thoughts?

Upvotes: 1

Views: 983

Answers (1)

veritas1
veritas1

Reputation: 9170

Solution:

remove attr_accessor :password, :password_confirmation from your User model.

Reason:

First, understand the difference between attr_accessor and attr_accessible - there are many good explanations on SO already eg:

Difference between attr_accessor and attr_accessible

As ruby interprets the User model one line at a time it gets to:

attr_accessible :first, :last, :email, :password, :password_confirmation

Which is fine.....until the very next line:

attr_accessor :password, :password_confirmation

When it overrides the :password and :password_confirmation attributes to make them attr_accessor

Which is why the error occurred it your specs when you called @user.save

Hope that helps.

Upvotes: 3

Related Questions