4
votes

Very simple spec...

@post.user.should == @user

Spec fails even though both objects are identical in every way except their object_id. ActiveRecord objects should equal (==) if their id's are the same. The objects are being created using factory_girl. I've confirmed that neither object is a ".new_record?". Comparing @post.user.id and @user.id works.

Whats more is the behavior is not consistent. These tests were working and now they fail despite no changes.

  • Rails 3.1
  • rspec-2.6
  • factory_girl-2.0.5
  • factory_girl_rails-1.1.0
  • jruby 1.6.4 (ruby-1.9.2-p136)
  • windows7

I typically use spork but this happens without spork also.

Some more details:

The offending line of code appears to be the following in ActiveRecord::Base

def ==(comparison_object)
  super ||
    comparison_object.instance_of?(self.class) &&
    id.present? &&
    comparison_object.id == id
end

Specifically, the "instance_of?" check is failing when it shouldn't be. I checked the class hierarchy of both objects. However, when I check the class.id of each object, they are not equal.

Furthermore, the behavior is dependant on which command I run...

jruby -S bundle exec rspec spec (FAILS)
jruby -S bundle exec rspec spec\models (PASSES)
jruby -S bundle exec rspec spec\models\post_spec.rb (PASSES)

Setting cache_classes=true in my environments/test.rb file seems to fix this, but I don't think this should be necessary.

2
have you tried this in console? moreover, have you tried this with another ruby VM such as MRI instead of jruby?Andrea Pavoni
I have the same problem when using MRILelon
How do you create them with FactoryGirl?Serabe
I only create the user with FactoryGirl... "user = Factory(:user)", inside a "before" block at the very top of the spec. The post is created with user.post.build (inside another before block). Inside factories.rb I have a Factory.define with my user attributes. (stackoverflow prevents me from adding @ in some places in comments)Lelon
Can you post the entire spec? Maybe there's some stubbing going on that's confusing things.Joost Baaij

2 Answers

1
votes

This ended up being really silly. The problem was I had my integration tests in /spec/integration instead of /spec/requests. Rspec/Rails was doing its loading magic in a specific set of directories only, but would run all tests from all directories (causing double loading).

-1
votes

These objects have different object_ids because of the way active record works. In the example you gave

@post.user.should == @user

@post.user and @user are completely separate objects in memory. Even if they are instances of the same class, and they have the same id field, they will never have the same object_id (apparently as long as cache_classes=false).

Other ORMs, such as data mapper, handle this with an identity map. In Rails 3.1 there is experimental identity map support in active record, but it is disabled by default.

See identity_map.rb for more info