---
title: Factory Bot Callbacks
teaser:
tags: news,web,ruby,testing,open source,factory_girl,factory_bot
author: Dan Croak
published_on: 2009-11-23
---

Factory Bot now has callbacks thanks to [Nate Sutton](http://github.com/nate).

![this shit is bananas](https://thoughtbot-training.s3.amazonaws.com/images/this-shit-bananas.jpg)

There are three callbacks:

    after(:build)
    after(:create)
    after(:stub)

When `build(:user)` is invoked, the `after(:build)` callback runs after building
the user. Likewise for `create` and `stub`.

These come in handy in a number of common use cases.

## Basic has many associations

Models:

    class Article < ActiveRecord::Base
      has_many :comments
    end

    class Comment < ActiveRecord::Base
      belongs_to :article
    end

Factories:

    factory :article do
      body { 'password' }

      factory :article_with_comment do
        after(:create) do |article|
          create(:comment, article: article)
        end
      end
    end

    factory :comment do
      body { 'Great article!' }
    end

Nice. Callbacks let us do this:

    article = create(:article_with_comment)

Instead of this:

    article = create(:article)
    create(:comment, article: article)

## Polymorphic relationships

The savings get larger when the object graph gets more complex:

Models:

    class User < ActiveRecord::Base
      has_many :interests, as: :interested
      has_many :topics, through: :interests
    end

    class Interest < ActiveRecord::Base
      belongs_to :topic
      belongs_to :interested, polymorphic: true
    end

Building block factories:

    factory :user
      email
      password { 'password' }

      factory :email_confirmed_user do
        email_confirmed { true }
      end
    end

    factory :topic do
      name { 'topic_name' }
    end

    factory :interest
      topic
      interested factory: :user
    end

    factory :music_interest, class: 'Interest' do
      topic.association(:topic, name: 'Music')
    end

    factory :sports_interest, class: 'Interest' do
      topic.association(:topic, name: 'Sports')
    end

And now the payoff:

    factory :musical_user, parent: :email_confirmed_user do
      after(:create) { |user| create(:music_interest, interested: user)
    end

    factory :sporty_user, parent: :email_confirmed_user do
      after(:create) { |user| create(:sports_interest, interested: user) }
    end

Again, factories let us do this:

    user = create(:musical_user)

Instead of:

    user = create(:email_confirmed_user)
    create(:music_interest, interested: user)

More intention-revealing. More encapsulation, protecting us from change.

## Working with fakes

[Fakes](https://thoughtbot.com/blog/post/219216005/fake-it) are a good
approach for testing objects that interface with web services such as geocoding
and payment processing.

    class User < ActiveRecord::Base
      acts_as_mappable
      before_validation :geocode_location, if: :location_changed?

      def geocode_location
        geo = Geokit::Geocoders::MultiGeocoder.geocode(location)
        self.lat, self.lng = geo.lat, geo.lng
      end
    end

    factory :user do
      factory :boston_user do
        location { 'Boston, MA' }

        after(:build) do |user|
          Geokit::Geocoders::FakeGeocoder.locations['Boston, MA'] = [0, 1]
        end
      end
    end

## Enjoy

Install:

    gem 'factory_bot'

Happy testing.

* * *

**Disclaimer:**

Looking for FactoryGirl? The library was renamed in 2017.
[Project name history can be found here.](https://github.com/thoughtbot/factory_bot/blob/master/NAME.md)
