Reputation: 97
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
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