'AssociationTypeMismatch and FactoryGirl

This has been causing some frustration recently...

It seems that using Factories in my cucumber tests, in some situations causes AssociationTypeMismatch errors such as:

MyModel(#65776650) expected, got MyModel(#28190030) (ActiveRecord::AssociationTypeMismatch)

These seem to happen when there is an association reference - as if the Factory created object is different to the real one. See this question for more details: Cucumber duplicate class problem: AssociationTypeMismatch

I have been gradually changing Factory calls to real Model.create or mock_model calls. It would be nice to keep using Factory girl... I wonder if there is something I may have done wrong?

Thank you



Solution 1:[1]

I had this happening with me on Rails 3.1.0 rc5, and got it working.

To expand on Jonas' answer.

You should change your Gemfile to be like this:

gem 'factory_girl', '~> 2.0.0', :require => false
gem 'factory_girl_rails', '~> 1.1.0', :require => false

And then if you are using Spork, make your spec/spec_helper.rb file look like this:

Spork.each_run do
 require 'factory_girl'
 require 'factory_girl_rails'
end

Solution 2:[2]

It seems to happen if ActiveSupport unloads and reloads a constant that you have a reference to. I've experienced the same with Rspec/Capybara, and what helped was a mixture of different things:

  • Make sure you have cached_classes set to false in your test environment (config/environments/test.rb)
  • In your gemspec, try replacing require 'factory_girl_rails' with 'factory_girl'

I'm using Spork (a test server), which seems to make this stuff increasingly difficult. If you are using a test server, evaluate whether you should put ', :require => false' after factory_girl in your gemspec.

The topic is also covered in this google groups thread

Please let us know if any of this helped.

Solution 3:[3]

If you're using Spork, make sure to reload your factories after reloading your models.

E.g.

Spork.each_run
  if Spork.using_spork?
    print "Reloading models ... "
    ActiveSupport::Dependencies.clear
    puts "done"

    print "Reloading factories ... "
    FactoryGirl.reload
    puts "done"
  end
end

Solution 4:[4]

This happens because cache_classes is false, as is required by Spork. Capybara reloads Rails classes for every request (or, to be correct, Rails' reloader middleware does, which is not called for normal tests), and this freaks out the factories (exactly why, I'm not sure). You can either reload them, or simply run your Capybara specs outside of Spork.

So you need two things: to only run Capybara outside of Spork, and to set cache_classes to false only for Spork.

To only run Capybara outside of Spork, I have a Guardfile that runs specs in spec/requests outside of Spork and other specs inside of Spork here:

https://gist.github.com/1731900

Then, in config/environments/test.rb:

config.cache_classes = !ENV['DRB']

Your Capybara specs will be a bit slower, as they need to boot rails, but everything will Just Work.

Solution 5:[5]

I had some success with reloading the Factory definitions try something like this:

class Factory
  def self.reload_definitions #:nodoc:
    self.factories.clear
    definition_file_paths.each do |path|
      load("#{path}.rb") if File.exists?("#{path}.rb")

      if File.directory? path
        Dir[File.join(path, '*.rb')].each do |file|
          load file
        end
      end
    end
  end
end

Solution 6:[6]

I ran into this issue when I passed the "class" option to my factory that was inherited by other factories:

factory :draft_resource, :class => Resource do

factory :resource, :parent => :draft_resource do

The only solution I could find was to simply not do this.

Solution 7:[7]

I ran into this same issue and spent probably ten hours trying every solution on this thread and everywhere else on the web. I started ripping out huge chunks of code trying to get it as close to another app of mine in which I couldn't reproduce the problem. Finally, I came across some helper functions in my spec_helper file:

def sign_in(user)              
  visit signin_path            
  fill_in "Email",    with: user.email
  fill_in "Password", with: user.password 
  click_button "Sign in"       

  # Sign in when not using Capybara as well.
  cookies[:remember_token] = user.remember_token if defined?(cookies)
end

A sign_in helper intended to work both in controller and request specs. And it does, sort of--just not with spork. When I removed the capybara helpers the issue was resolved:

def sign_in(user)              
  cookies[:remember_token] = user.remember_token
end

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 staackuser2
Solution 2 Community
Solution 3 duma
Solution 4 bhuga
Solution 5 Lars Klevan
Solution 6 gabeodess
Solution 7 lobati