Rspec causing validates_presence_of to validate twice?

I had posted this on the regular Rails list, but upon trying this in
script/console, it seems like the behavior only exists when running
rspec.

I’m getting some weird behavior in one of my models. I have a model
defined something like this

class User < ActiveRecord::Base
attr_accessor :password

validates_presence_of :password
end

If I validate the model without specifying a password, I get [“can’t be
blank”, “can’t be blank”] for :password instead of just one “cant’t be
blank”. If I comment out the validates_presence_of statement, then no
errors. So it doesn’t seem like it’s being defined elsewhere(through a
plugin or some such). Any idea what might be going on here?

Like mentioned above, if I do this in script/console I only get “can’t
be
blank” once, as expected.

I should note that I’m not blaming rspec, moreso, where should I be
starting to look? My spec looks like this(snipped the other passing
tests):

describe User do
include UserExampleHelperMethods

before(:each) do
@user = User.new
@user.password = ‘123456’
@user.password_confirmation = ‘123456’
end

it ‘should be invalid without a password when creating’ do
@user.attributes = valid_user_attributes
@user.password = nil
@user.password_confirmation = nil
@user.should_not be_valid
@user.errors.on(:password).should == “can’t be blank”
end
end

Versions? RSpec? Rails?

On Wed, 17 Oct 2007 15:05:01 -0500, David C. wrote:

Versions? RSpec? Rails?

Details details. :slight_smile:

rspec/rspec_on_rails(trunk): r2717
rails(trunk): r7822

On Wed, 17 Oct 2007 15:41:19 -0500, David C. wrote:

Please update to the latest rspec trunk and try again. I think this is
due to a bug that was resolved in the 2718 (believe it or not).

Just updated and am at 2719. The problem still happens.

On 10/17/07, Steve [email protected] wrote:

On Wed, 17 Oct 2007 15:05:01 -0500, David C. wrote:

Versions? RSpec? Rails?

Details details. :slight_smile:

rspec/rspec_on_rails(trunk): r2717
rails(trunk): r7822

Please update to the latest rspec trunk and try again. I think this is
due to a bug that was resolved in the 2718 (believe it or not).

On Wed, 17 Oct 2007 21:12:27 +0000, Steve wrote:

On Wed, 17 Oct 2007 15:41:19 -0500, David C. wrote:

Please update to the latest rspec trunk and try again. I think this is
due to a bug that was resolved in the 2718 (believe it or not).

Just updated and am at 2719. The problem still happens.

May or may not be relevant, but I have other validates_presence_of
calls,
and they all work exactly as expected.

On Wed, 17 Oct 2007 16:17:53 -0500, David C. wrote:

Thanks for trying. Sorry it’s still a problem.

How are you running the specs (rake? spec command? textmate?) and what
precisely is the error that you get? Please include a stack trace (not
just one line)

Thanks,
David

I’m running through rake(rake spec:models to be exact). The error is:

‘User should be invalid without a password when creating’ FAILED
expected: “can’t be blank”,
got: [“can’t be blank”, “can’t be blank”] (using ==)
./spec/models/user_spec.rb:64:

So there isn’t an actual ruby error, it’s just the errors collection not
matching.

This is the output from rake with the --trace option

/trunk/vendor/plugins/rspec/lib/spec/rake/spectask.rb:173:in define' /usr/lib/ruby/gems/1.8/gems/rake-0.7.3/lib/rake.rb:823:inverbose’
/trunk/vendor/plugins/rspec/lib/spec/rake/spectask.rb:142:in define' /usr/lib/ruby/gems/1.8/gems/rake-0.7.3/lib/rake.rb:392:incall’
/usr/lib/ruby/gems/1.8/gems/rake-0.7.3/lib/rake.rb:392:in execute' /usr/lib/ruby/gems/1.8/gems/rake-0.7.3/lib/rake.rb:392:ineach’
/usr/lib/ruby/gems/1.8/gems/rake-0.7.3/lib/rake.rb:392:in execute' /usr/lib/ruby/gems/1.8/gems/rake-0.7.3/lib/rake.rb:362:ininvoke’
/usr/lib/ruby/1.8/thread.rb:135:in synchronize' /usr/lib/ruby/gems/1.8/gems/rake-0.7.3/lib/rake.rb:355:ininvoke’
/usr/lib/ruby/gems/1.8/gems/rake-0.7.3/lib/rake.rb:1739:in top_level' /usr/lib/ruby/gems/1.8/gems/rake-0.7.3/lib/rake.rb:1739:ineach’
/usr/lib/ruby/gems/1.8/gems/rake-0.7.3/lib/rake.rb:1739:in top_level' /usr/lib/ruby/gems/1.8/gems/rake-0.7.3/lib/rake.rb:1761:instandard_exception_handling’
/usr/lib/ruby/gems/1.8/gems/rake-0.7.3/lib/rake.rb:1733:in top_level' /usr/lib/ruby/gems/1.8/gems/rake-0.7.3/lib/rake.rb:1711:inrun’
/usr/lib/ruby/gems/1.8/gems/rake-0.7.3/lib/rake.rb:1761:in
standard_exception_handling' /usr/lib/ruby/gems/1.8/gems/rake-0.7.3/lib/rake.rb:1708:inrun’
/usr/lib/ruby/gems/1.8/gems/rake-0.7.3/bin/rake:7
/usr/bin/rake:16:in `load’
/usr/bin/rake:16

On 10/17/07, Steve [email protected] wrote:

I’m running through rake(rake spec:models to be exact). The error is:

‘User should be invalid without a password when creating’ FAILED
expected: “can’t be blank”,
got: [“can’t be blank”, “can’t be blank”] (using ==)
./spec/models/user_spec.rb:64:

So there isn’t an actual ruby error, it’s just the errors collection not
matching.

Would you please try running it like this:

script/spec spec -b

and this

script/spec spec/models/user_spec.rb -b

and let us know if it’s still happening?

On 10/17/07, Steve [email protected] wrote:

On Wed, 17 Oct 2007 15:41:19 -0500, David C. wrote:

Please update to the latest rspec trunk and try again. I think this is
due to a bug that was resolved in the 2718 (believe it or not).

Just updated and am at 2719. The problem still happens.

Thanks for trying. Sorry it’s still a problem.

How are you running the specs (rake? spec command? textmate?) and what
precisely is the error that you get? Please include a stack trace (not
just one line)

Thanks,
David

On Wed, 17 Oct 2007 16:40:11 -0500, David C. wrote:

Would you please try running it like this:

script/spec spec -b

and this

script/spec spec/models/user_spec.rb -b

and let us know if it’s still happening?

script/spec spec -b changes things. It doesn’t give that duplication of
validations for password presence, but does it on two other tests(which
pass using rake spec:models):

‘User with a new password should check that the password is 6-15
characters long’ FAILED
expected: “is too short (minimum is 6 characters)”,
got: [“is too short (minimum is 6 characters)”, “is too short
(minimum is 6 characters)”] (using ==)
/trunk/vendor/plugins/rspec/lib/spec/expectations.rb:52:in fail_with' /trunk/vendor/plugins/rspec/lib/spec/matchers/operator_matcher.rb:46:infail_with_message’
/trunk/vendor/plugins/rspec/lib/spec/matchers/operator_matcher.rb:56:in
__delegate_method_missing_to_target' /trunk/vendor/plugins/rspec/lib/spec/matchers/operator_matcher.rb:12:in==’
/trunk/spec/models/user_spec.rb:138:
/trunk/vendor/plugins/rspec/lib/spec/dsl/example_module.rb:171:in
instance_eval' /trunk/vendor/plugins/rspec/lib/spec/dsl/example_module.rb:171:inrun_example’
/trunk/vendor/plugins/rspec/lib/spec/dsl/example_runner.rb:65:in
run_example' /trunk/vendor/plugins/rspec/lib/spec/dsl/example_runner.rb:26:inrun’
/usr/lib/ruby/1.8/timeout.rb:48:in timeout' /trunk/vendor/plugins/rspec/lib/spec/dsl/example_runner.rb:24:inrun’
/trunk/vendor/plugins/rspec/lib/spec/dsl/example_suite.rb:26:in
rspec_run' /trunk/vendor/plugins/rspec/lib/spec/dsl/example_suite.rb:22:ineach’
/trunk/vendor/plugins/rspec/lib/spec/dsl/example_suite.rb:22:in
rspec_run' /trunk/vendor/plugins/rspec/lib/spec/test/unit/example_suite.rb:7:inrun’
/trunk/vendor/plugins/rspec/lib/spec/runner/behaviour_runner.rb:12:in
run' /trunk/vendor/plugins/rspec/lib/spec/runner/behaviour_runner.rb:11:ineach’
/trunk/vendor/plugins/rspec/lib/spec/runner/behaviour_runner.rb:11:in
run' /trunk/vendor/plugins/rspec/lib/spec/runner/options.rb:71:inrun_examples’
/trunk/vendor/plugins/rspec/lib/spec/runner/command_line.rb:22:in `run’
script/spec:4:

‘User with a new password should check for confirmation of the new
password’ FAILED
expected: “doesn’t match confirmation”,
got: [“doesn’t match confirmation”, “doesn’t match confirmation”]
(using ==)
/trunk/vendor/plugins/rspec/lib/spec/expectations.rb:52:in fail_with' /trunk/vendor/plugins/rspec/lib/spec/matchers/operator_matcher.rb:46:infail_with_message’
/trunk/vendor/plugins/rspec/lib/spec/matchers/operator_matcher.rb:56:in
__delegate_method_missing_to_target' /trunk/vendor/plugins/rspec/lib/spec/matchers/operator_matcher.rb:12:in==’
/trunk/spec/models/user_spec.rb:154:
/trunk/vendor/plugins/rspec/lib/spec/dsl/example_module.rb:171:in
instance_eval' /trunk/vendor/plugins/rspec/lib/spec/dsl/example_module.rb:171:inrun_example’
/trunk/vendor/plugins/rspec/lib/spec/dsl/example_runner.rb:65:in
run_example' /trunk/vendor/plugins/rspec/lib/spec/dsl/example_runner.rb:26:inrun’
/usr/lib/ruby/1.8/timeout.rb:48:in timeout' /trunk/vendor/plugins/rspec/lib/spec/dsl/example_runner.rb:24:inrun’
/trunk/vendor/plugins/rspec/lib/spec/dsl/example_suite.rb:26:in
rspec_run' /trunk/vendor/plugins/rspec/lib/spec/dsl/example_suite.rb:22:ineach’
/trunk/vendor/plugins/rspec/lib/spec/dsl/example_suite.rb:22:in
rspec_run' /trunk/vendor/plugins/rspec/lib/spec/test/unit/example_suite.rb:7:inrun’
/trunk/vendor/plugins/rspec/lib/spec/runner/behaviour_runner.rb:12:in
run' /trunk/vendor/plugins/rspec/lib/spec/runner/behaviour_runner.rb:11:ineach’
/trunk/vendor/plugins/rspec/lib/spec/runner/behaviour_runner.rb:11:in
run' /trunk/vendor/plugins/rspec/lib/spec/runner/options.rb:71:inrun_examples’
/trunk/vendor/plugins/rspec/lib/spec/runner/command_line.rb:22:in `run’
script/spec:4:

script/spec spec/models/user_spec.rb -b yields the same as above.

On 10/17/07, Steve [email protected] wrote:

and let us know if it’s still happening?
/trunk/vendor/plugins/rspec/lib/spec/matchers/operator_matcher.rb:46:in fail_with_message' /trunk/vendor/plugins/rspec/lib/spec/dsl/example_suite.rb:22:in each’
‘User with a new password should check for confirmation of the new password’ FAILED
/trunk/vendor/plugins/rspec/lib/spec/dsl/example_runner.rb:26:in run' /trunk/vendor/plugins/rspec/lib/spec/runner/command_line.rb:22:in run’
script/spec:4:

script/spec spec/models/user_spec.rb -b yields the same as above.

One more thing to try. Open up spec/spec.opts and remove the line that
says “–reverse” if it’s there. Then run “rake spec” again and see
what happens.

Thanks,
David

On Wed, 17 Oct 2007 18:01:11 -0500, David C. wrote:

One more thing to try. Open up spec/spec.opts and remove the line that
says “–reverse” if it’s there. Then run “rake spec” again and see
what happens.

Thanks,
David

Removing --reverse makes “rake spec” fail like the other two methods
now.
Which one is the correct failure?

On Wed, 17 Oct 2007 19:30:57 -0500, David C. wrote:

see the entire file to help you figure out why. If you feel like posting
it, please pastie it and write back.

I take that back, “rake spec” causes similar failure, in that those
double
validation messages appear, but it also adds two failures that weren’t
there before.

‘User should have a case-insensitive unique username’ FAILED expected
valid? to return false, got true ./spec/helpers/…/spec_helper.rb:49:in
check_unique' ./spec/models/user_spec.rb:101:incheck_user_unique’
./spec/models/user_spec.rb:28:

‘User should have a case-insensitive unique email address’ FAILED
expected
valid? to return false, got true ./spec/helpers/…/spec_helper.rb:49:in
check_unique' ./spec/models/user_spec.rb:101:incheck_user_unique’
./spec/models/user_spec.rb:40:

If I run “script/spec spec” those don’t appear, and I just have the
double
validation message errors.

Also I really don’t think I’m leaking state. I have before(:each)
statements in my “describes” that
basically create new instances of the object as required for that
behavior. So they are fresh each time, correct? Further, even though
rails
clears the errors collection when valid? is called, I called
@user.errors.clear before attempting the validations that are failing
with
the double message just to be sure, and it’s still happening. Again,
these
problems don’t happen in script/console at all, but it is validating
correctly.

On 10/17/07, Steve [email protected] wrote:

Also I really don’t think I’m leaking state. I have before(:each) statements in my “describes” that
basically create new instances of the object as required for that
behavior. So they are fresh each time, correct? Further, even though rails
clears the errors collection when valid? is called, I called
@user.errors.clear before attempting the validations that are failing with
the double message just to be sure, and it’s still happening. Again, these
problems don’t happen in script/console at all, but it is validating
correctly.

This all may be true but I can’t help you diagnose the problem without
looking at the code. If you’d kindly pastie the spec and model, I’ll
be glad to look at them. Otherwise I’m just guessing and that’s not
working out to well so far.

On Wed, 17 Oct 2007 21:31:19 -0500, David C. wrote:

This all may be true but I can’t help you diagnose the problem without
looking at the code. If you’d kindly pastie the spec and model, I’ll
be glad to look at them. Otherwise I’m just guessing and that’s not
working out to well so far.

Rather than burden you with it in its uber-long glory, I started trying
to
rebuild the file piecemeal until failure. What I found is that this
behavior was causing it to fail:

it ‘should only allow access to the username, first_name, last_name, and
email address fields’ do
#User.should_receive(:attr_accessible).with(:username, :first_name,
:last_name, :email_address)
#load “#{RAILS_ROOT}/app/models/user.rb”
end

You may recall that from a post I made a few days ago. It seems like a
“duh” moment now. Of course the “load” statement re-evals the class,
and just adds to the existing version that Ruby knows about. How would
you
get around this though? Can you?

On 10/17/07, Steve [email protected] wrote:

On Wed, 17 Oct 2007 18:01:11 -0500, David C. wrote:

One more thing to try. Open up spec/spec.opts and remove the line that
says “–reverse” if it’s there. Then run “rake spec” again and see
what happens.

Thanks,
David

Removing --reverse makes “rake spec” fail like the other two methods now.

That’s what I suspected would happen.

The reason they were failing differently was that rake was running
them in the opposite order. Removing --reverse made it so they run in
the same order.

So now, the problem is that your specs are leaking state. I’d need to
see the entire file to help you figure out why. If you feel like
posting it, please pastie it and write back.

On 10/17/07, Steve [email protected] wrote:

it ‘should only allow access to the username, first_name, last_name, and email address fields’ do
#User.should_receive(:attr_accessible).with(:username, :first_name, :last_name, :email_address)
#load “#{RAILS_ROOT}/app/models/user.rb”
end

You may recall that from a post I made a few days ago. It seems like a
“duh” moment now. Of course the “load” statement re-evals the class,
and just adds to the existing version that Ruby knows about. How would you
get around this though? Can you?

You’d have to make sure that every declaration in the file is stubbed.
Probably the best way would be to do this:

describe User, “declarations” do
before(:each) do
User.stub!(:attr_accessible)
User.stub!(:validates_presence_of)
end

it “should assign attrs accessible” do
User.should_receive(:attr_accessible).with(:username, :first_name,
:last_name, :etc)
load “#{RAILS_ROOT}/app/models/user.rb”
end

it “should validate presence of password” do
User.should_receive(:attr_accessible).with(:username, :first_name,
:last_name, :etc)
load “#{RAILS_ROOT}/app/models/user.rb”
end
end

Kind of hideous, but it should work.