FactoryGirl screws up rake db:migrate process
Asked Answered
H

4

32

I am doing TDD/BDD in Ruby on Rails 3 with Rspec (2.11.0) and FactoryGirl (4.0.0). I have a factory for a Category model:

FactoryGirl.define "Category" do
  factory :category do
    name "Foo"
  end
end

If I drop, create then migrate the database in the test enviroment I get this error:

rake aborted!
Could not find table 'categories'

This problem occurs because FactoryGirl expects the tables to already exist (for some odd reason). If I remove the spec folder from my rails app and do db:migrate, it works. Also if I mark factory-girl-rails from my Gemfile as :require => false it also works (then I have to comment that require in order to run rspec).

I found some information about this problem here: https://github.com/thoughtbot/factory_girl/issues/88

Is there something wrong that I'm doing? How can I "pass by" the FactoryGirl stage in the db:migration task?

Horal answered 14/9, 2012 at 11:6 Comment(0)
T
79

I think you need to have factory girl definition like that in Gemfile:

  gem 'factory_girl_rails', :require => false

And then you just require it in your spec_helper.rb like that:

  require 'factory_girl_rails'

This is the way I'm always using this gem. You don't need to require it in other places than spec_helper.rb. Your current desired approach is just wrong.

Trinidadtrinitarian answered 14/9, 2012 at 13:37 Comment(6)
This exception that ruins your rake is what rspec should handle when you run your tests(so it will mark specs as not passing). Your approach is wrong because it cannot work the way you want it to.Trinidadtrinitarian
I ran into this exact problem and this fixed it - thanks so much!Acerbic
I faced this same issue with miniskirt gem. This answer fixes it in miniskirt as well.Christabelle
@VadimChumel Do you mind explaining a little bit why adding :require => false makes the error go away? I couldn't find any documentation in terms of this option in the repo. Also, like OP said, adding this option will result in errors when running rspec. Are there better solutions for this?Woodenware
@Woodenware It fixes it as requiring the gem before would make it load the files that gem requires which happens to be factories.rb. As the table doesn't exist if factory file tries to load the class Category and while loading the class if something required the table to be present it will error out. When you run rspec you can require it before and then if the table exists it should be able to load the factories fine.Ground
Thx @VadimChumel this fixed an issue we were facing on our CodeShip builds for test environment.Calley
H
12

A simple fix to this issue is to delay evaluation of any models in your factories by wrapping them in blocks. So, instead of this:

factory :cake do
  name "Delicious Cake"
  frosting Frosting.new(:flavor => 'chocolate')
  filling Filling.new(:flavor => 'red velvet')
end

Do this (notice the curly braces):

factory :cake do
  name "Delicious Cake in a box"
  frosting { Frosting.new(:flavor => 'chocolate') }
  filling { Filling.new(:flavor => 'red velvet') }
end

If you have a lot of factories this may not be feasible, but it is rather straightforward. See also here.

Hulse answered 10/12, 2012 at 8:28 Comment(2)
I needed this answer (although I also applied the advice about setting require=false on the factory_girl Gemfile listing. ) FactoryGirl was attempting to create objects when the environment was being loaded, before creating the tables.Sash
This is the answer that ended up fixing it for me.Mayworm
H
3

Information from: http://guides.rubyonrails.org/testing.html

When you do end up destroying your testing database (and it will happen, trust me), you can rebuild it from scratch according to the specs defined in the development database. You can do this by running rake db:test:prepare.

The rake db:migrate above runs any pending migrations on the development environment and updates db/schema.rb. The rake db:test:load recreates the test database from the current db/schema.rb. On subsequent attempts, it is a good idea to first run db:test:prepare, as it first checks for pending migrations and warns you appropriately.

rake db:test:clone            Recreate the test database from the current environment’s database schema
rake db:test:clone_structure  Recreate the test database from the development structure
rake db:test:load             Recreate the test database from the current schema.rb
rake db:test:prepare          Check for pending migrations and load the test schema
rake db:test:purge            Empty the test database.
Horal answered 14/9, 2012 at 13:39 Comment(0)
W
1

You shouldn't need to do any of that.. I think the issue is that your argument to FactoryGirl.define..

try this.

FactoryGirl.define do
   factory :category do
       name "Foo"
   end
end

That should work fine, and does not screw up my migrations or load.. Today, I had to fix an issue where I was referencing a model constant from my factory directly and had to put it in a block to fix things.

FactoryGirl.define do
   factory :category do
       # this causes unknown table isseus
       # state Category::Active
       # this does not.
       state { Category::Active }
   end
end
Watercolor answered 11/2, 2013 at 22:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.