35bb9409aa
Fixes #336 Before this commit, the initialization process looked like this: Rails runs all of the initializers 1. Run the ["factory_bot.set_factory_paths"][set_factory_paths] initializer 2. Run the ["factory_bot.register_reloader"][register_reloader] initializer, which sets up a [prepare callback][] 3. Run the [`:run_prepare_callbacks`][] initializer 4. This triggers the factory_bot [prepare callback][], which causes factory\_bot to [reload][] Rails runs `after_initialize` callbacks 1. [I18n initializes] 2. factory\_bot [reloads again][] as described in #334 The double reloading of factory_bot in this initialization is not ideal, but also shouldn't generally cause any problems on its own. The problems people are having in #336 come from the fact that I18n gets set up in an `after_initialize` callback, but factory_bot gets reloaded before the `after_initialize` callbacks are triggered. If the `FactoryBot.define` block references any code that uses I18n translations as it loads, that code will raise an error (references inside other factory_bot methods, or code that uses I18n translations inside of methods still works fine, since the whole Rails initialization process would be complete by the time any of that code runs). This commit moves factory_bot reloading from a prepare callback into an `after_initialize` callback. This allows us to avoid reloading factory_bot before I18n is loaded, and also gets rid of that pesky double reloading of factory_bot. The new initialization process looks like: Rails runs all of the initializers 1. Run the ["factory_bot.set_factory_paths"][set_factory_paths] 2. Run the [`:run_prepare_callbacks`][] initializer, which no longer involves factory_bot Rails runs `after_intialize` callbacks 1. [I18n initializes] 2. Run the factory_bot reloader, which sets up the prepare callback for any future prepares (for example calling `reload!` in the console), and executes the reloader to run the initial `FactoryBot.reload` [set_factory_paths]: |
||
---|---|---|
bin | ||
features | ||
gemfiles | ||
lib | ||
spec | ||
.gitignore | ||
.hound.yml | ||
.rspec | ||
.rubocop.yml | ||
.travis.yml | ||
Appraisals | ||
CODE_OF_CONDUCT.md | ||
CONTRIBUTING.md | ||
factory_bot_rails.gemspec | ||
Gemfile | ||
Gemfile.lock | ||
LICENSE | ||
NEWS.md | ||
Rakefile | ||
README.md | ||
RELEASING.md |
factory_bot_rails
factory_bot is a fixtures replacement with a straightforward definition
syntax, support for multiple build strategies (saved instances, unsaved
instances, attribute hashes, and stubbed objects), and support for multiple
factories for the same class (user
, admin_user
, and so on), including factory
inheritance.
Transitioning from factory_girl_rails?
Check out the guide.
Rails
factory_bot_rails provides Rails integration for factory_bot.
Supported Rails versions are listed in Appraisals
. Supported
Ruby versions are listed in .travis.yml
.
Download
Github: http://github.com/thoughtbot/factory_bot_rails
Gem:
$ gem install factory_bot_rails
Configuration
Add factory_bot_rails
to your Gemfile in both the test and development groups:
group :development, :test do
gem 'factory_bot_rails'
end
You may want to configure your test suite to include factory_bot methods; see configuration.
Automatic Factory Definition Loading
By default, factory_bot_rails will automatically load factories defined in the following locations, relative to the root of the Rails project:
factories.rb
test/factories.rb
spec/factories.rb
factories/*.rb
test/factories/*.rb
spec/factories/*.rb
You can configure by adding the following to config/application.rb
or the
appropriate environment configuration in config/environments
:
config.factory_bot.definition_file_paths = ["custom/factories"]
This will cause factory_bot_rails to automatically load factories in
custom/factories.rb
and custom/factories/*.rb
.
It is possible to use this setting to share factories from a gem:
begin
require 'factory_bot_rails'
rescue LoadError
end
class MyEngine < ::Rails::Engine
config.factory_bot.definition_file_paths +=
[File.expand_path('../factories', __FILE__)] if defined?(FactoryBotRails)
end
You can also disable automatic factory definition loading entirely by using an empty array:
config.factory_bot.definition_file_paths = []
Generators
Including factory_bot_rails in the development group of your Gemfile will cause Rails to generate factories instead of fixtures. If you want to disable this feature, you can either move factory_bot_rails out of the development group of your Gemfile, or add the following configuration:
config.generators do |g|
g.factory_bot false
end
If fixture replacement is enabled and you already have a test/factories.rb
file (or spec/factories.rb
if using rspec_rails), generated factories will be
inserted at the top of the existing file.
Otherwise, factories will be generated in the
test/factories
directory (spec/factories
if using rspec_rails),
in a file matching the name of the table (e.g. test/factories/users.rb
).
To generate factories in a different directory, you can use the following configuration:
config.generators do |g|
g.factory_bot dir: 'custom/dir/for/factories'
end
Note that factory_bot_rails will not automatically load files in custom
locations unless you add them to config.factory_bot.definition_file_paths
as
well.
The suffix option allows you to customize the name of the generated file with a suffix:
config.generators do |g|
g.factory_bot suffix: "factory"
end
This will generate test/factories/users_factory.rb
instead of
test/factories/users.rb
.
For even more customization, use the filename_proc
option:
config.generators do |g|
g.factory_bot filename_proc: ->(table_name) { "prefix_#{table_name}_suffix" }
end
To override the default factory template, define your own template in
lib/templates/factory_bot/model/factories.erb
. This template will have
access to any methods available in FactoryBot::Generators::ModelGenerator
.
Note that factory_bot_rails will only use this custom template if you are
generating each factory in a separate file; it will have no effect if you are
generating all of your factories in test/factories.rb
or spec/factories.rb
.
Contributing
Please see CONTRIBUTING.md.
factory_bot_rails was originally written by Joe Ferris and is now maintained by Josh Clayton. Many improvements and bugfixes were contributed by the open source community.
License
factory_bot_rails is Copyright © 2008-2019 Joe Ferris and thoughtbot. It is free software, and may be redistributed under the terms specified in the LICENSE file.
About thoughtbot
factory_bot_rails is maintained and funded by thoughtbot, inc. The names and logos for thoughtbot are trademarks of thoughtbot, inc.
We are passionate about open source software. See our other projects. We are available for hire.