
factory_girl has always had little Rails-specific code. It only depends on Ruby, and in order to use it in your application, it asks three things of your models:
#save! (this is only necessary for the “create” strategy)However, despite this simple API, there’s one feature in factory_girl that has traditionally caused some issues with Rails: automatic factory definition loading.
The definition loader has simple rules: if it finds any of test/factories.rb, spec/factories.rb, test/factories/**/*.rb, or spec/factories/**/*.rb, it will load those files in no particular order. For most applications, this just makes things a little nicer.
In early versions of factory_girl, it looked for definitions as soon as you loaded factory_girl.rb. Unfortunately, this broke down when Rails 2.1 introduced gem dependency management. Loading factory_girl during the application initialization phase meant that the factory definitions might reference your models before all the gems and plugins they depended on were fully loaded. Contributer technicalpickles fixed that by detecting Rails and deferring definition loading until Rails was initialized. This solution worked effectively for the entire Rails 2.x series of releases.
The upcoming Rails 3 release uses a new library for managing application dependencies: bundler. Bundler’s behavior is more predictable and understandable than Rails 2’s dependency manager ever was. However, with the introduction of Bundler, two important changes were introduced that impacted many libraries that integrate silently with each other:
Yehuda Katz, the author of Bundler, discussed this topic in depth on his blog. In his discussion, he suggests a solution that could be added to Rubygems:
s.integrates_with "rails", "~> 3.0.0.beta2", "haml/rails"
However, this functionality doesn’t exist yet, so we’ve decided to create a separate factory_girl_rails gem. This way, we can declare an explicit dependency on Rails, including the version, and automatic definition loading still takes place for Rails apps without any additional application code.
This doesn’t change much for an application that uses factory_girl. It boils down to this:
rails/init.rb and load your definitions.I originally added this feature to factory_girl because it was convenient, and seemed easy to add. However, this trivial feature has turned out to be the most difficult to maintain part of factory_girl, and is the single feature that is most likely to outright break an application. I plan on maintaining this feature because we’re used to having it and we’ve worked out most of the kinks at this point, but next time you consider adding an “easy” feature to your own library, also consider whether or not it’s essential to your library’s core mission.