Reputation: 279
I've been struggling with this for a few hours now and i can't find an answer anywhere.
Basically i'm writing specs for my models using shoulda and for some reason even though my let works just fine and the actual application works fine(confirmed manually and with request specs), if i include:
it { expect(user).to validate_uniqueness_of :email }
in my describe block, i will get the following error:
1) User attributes should require case sensitive unique value for email
Failure/Error: it { expect(user).to validate_uniqueness_of :email }
RuntimeError:
Password digest missing on new record
# ./spec/models/user_spec.rb:14:in `block (3 levels) in <top (required)>'
I've gotten to a point where solving this spec is holding me back, which is never a good thing, since the implementation already works.
It would be great if someone could help me out here because i REALLY don't want to start skipping tests that are failing for some obscure reason just to get things moving.
I feel as if rspec was 'ignoring' the before method that is called for has_secure_password to save the digest but i'm not sure. I'm just assuming because if the request spec worked fine, this is doing something i'm not aware of.
I'm using rails 4.0.0
Below is the relevant code to this. I appreciate any help. Thanks
user_spec.rb
require 'spec_helper'
describe User do
let(:user) {
user = User.new(:email => 'example@example.com',
:username => 'theo',
:password => 'secretpass',
:password_confirmation => 'secretpass')}
describe "attributes" do
it { expect(user).to validate_presence_of :email }
it { expect(user).to validate_uniqueness_of :email }
it { expect(user).to validate_presence_of :username }
it { expect(user).to validate_uniqueness_of :username }
it "saves are saved" do
user.save!
expect(user).to be_valid
end
end
end
user.rb
class User < ActiveRecord::Base
has_secure_password
validates :email, :username, presence: true, uniqueness: true
validates :password, presence: true, :on => :create
end
users_controller.rb
class UsersController < ApplicationController
def index
end
def new
@user = User.new
end
def create
@user = User.new(user_params)
if @user.save
redirect_to root_path, :notice => 'You have successfully signed up.'
else
render 'new'
end
end
private
def user_params
params.require(:user).permit(:email, :username, :password, :password_confirmation)
end
end
Upvotes: 0
Views: 1727
Reputation: 620
Answer to your question is here: https://github.com/thoughtbot/shoulda-matchers/issues/371
In short, here is the underlying issue:
It appears that the Rails 4 version of
has_secure_password
adds a before_create to ensure thatpassword_digest
is filled in; however, the Rails 3 version does not have this check.
Upvotes: 0
Reputation: 1845
Probably a bug in shoulda-matchers, maybe related to this one https://github.com/thoughtbot/shoulda-matchers/issues/290
Cheers
Upvotes: 0
Reputation: 3406
Please make sure you have password_digest exist in your User schema, details please see here
create_table “users”, force: true do |t|
……
t.text “password_digest”
…..
end
If it works in your development but not test, please check if you do the rake db:migration in test env, I mean RAILS_ENV=test rake db:migrate.
!!!Updated -- related to shouda-matchers
gocha
It seems a bug for shoulda-matchers
, cause when you do this the test will pass:
it "should be validate uniq of email " do
user.save
expect(user).to validate_uniqueness_of :email
end
the reason why I am doing the user.save
is because of this
, otherwise it will create a record for you, that will cause the error you got:
# https://github.com/thoughtbot/shoulda-matchers/blob/master/lib/shoulda/matchers/active_model/validate_uniqueness_of_matcher.rb#L126
def create_record_in_database(options = {})
if options[:nil_value]
value = nil
else
value = "arbitrary_string"
end
@subject.class.new.tap do |instance|
instance.send("#{@attribute}=", value)
instance.save(:validate => false) # the error happens here, not in your code
end
end
So above all, this is probably a bug of shouda-matchers
, though I didn't have time to figure out how to fix it, for now you can use this method as a work around, or use some other method to test this.
Hope it helps :-)
Upvotes: 5