---
title: Get Your Callbacks On with Factory Bot 3.3
teaser:
tags: web,open source,rails,testing,factory_girl,factory_bot
author: Josh Clayton
published_on: 2012-05-15
---

FactoryBot 3.3.0 was released this weekend with a slew of improvements.

To install, add (or change) your Gemfile:

    gem 'factory_bot_rails', '~> 3.3.0'

## New Callback Syntax

Callbacks have been revamped to work well in conjunction with custom
strategies. Instead of declaring callbacks like this:

    FactoryBot.define do
      factory :user do
        factory :user_with_posts do
          after(:create) {|instance| create_list(:post, 5, user: instance) }
        end
      end
    end

you can declare callbacks with `before` and `after`, passing the symbol of
the callback as the name:

    FactoryBot.define do
      factory :user do
        after(:custom) {|instance| instance.do_something_custom! }

        factory :user_with_posts do
          after(:create) {|instance| create_list(:post, 5, user: instance) }
        end
      end
    end

Finally, you can use completely custom callbacks without a before or after
prepended by just calling `callback`:

    FactoryBot.define do
      factory :user do
        callback(:custom_callback) {|instance| instance.do_something_custom! }
      end
    end

These work great with [custom
strategies](https://thoughtbot.com/blog/factorybot-3-2-so-awesome-it-needs-to-be-released):

    class CustomStrategy
      def initialize
        @strategy = FactoryBot.strategy_by_name(:create).new
      end

      delegate :association, to: :@strategy

      def result(evaluation)
        @strategy.result(evaluation).tap do |instance|
          evaluation.notify(:custom_callback, instance) # runs callback(:custom_callback)
          evaluation.notify(:after_custom, instance)    # runs after(:custom)
        end
      end
    end

## Support all `*_list` methods

FactoryBot already introduced `build_list` and `create_list` to build and create
an array of instances; in 3.3.0, `*_list` methods are generated dynamically
for all strategies registered, so `build_stubbed_list` and
`attributes_for_list` join the immediate roster of methods; if you were to
register a strategy named "insert", `insert_list` would exist as well.

## Fix `to_create` and `initialize_with` within traits

Traits are a great way to name an abstract concept of attributes, but for a
long time, they didn't support defining `to_create` or `initialize_with`.
3.3.0 fixes this shortcoming by having `to_create` and `initialize_with`
behave in traits exactly as you'd expect. This is perfect for decorating
objects from within FactoryBot.

    class NotifierDecorator < BasicObject
      undef_method :==

      def initialize(component)
        @component = component
      end

      def save!
        @component.save!.tap do
          Notifier.new(@component).notify("saved!")
        end
      end

      def method_missing(name, *args, &block)
        @component.send(name, *args, &block)
      end

      def send(symbol, *args)
        __send__(symbol, *args)
      end
    end

    FactoryBot.define do
      trait :with_notifications do
        to_create {|instance| NotifierDecorator.new(instance).save! }
      end

      factory :user
    end

    create(:user, :with_notifications) # decorates save! when the instance is created

    FactoryBot.define do
      trait :with_notifications do
        initialize_with { NotifierDecorator.new(new) }
      end

      factory :post
    end

    create(:post, :with_notifications) # returns a post instance decorated with NotifierDecorator

## Define `to_create` and `initialize_with` globally

If you're using an ORM other than ActiveRecord, you may want to call different
methods for persistence. Declaring a `to_create` (or `initialize_with`, if you
wanted to use a global decorator) within the `FactoryBot.define` block will
now apply to all declared factories, behaving much like sequences, traits, and
factories.

You can override the global `to_create` or `initialize_with` with traits or by
defining `to_create` in a factory explicitly.

    FactoryBot.define do
      to_create {|instance| instance.persist! }

      factory :user do
        factory :user_backed_by_active_record do
          to_create {|instance| instance.save! }
        end
      end
    end

## What's next

There are still cases where traits don't behave correctly (using implicit
traits is a big remaining bug) and more work for `initialize_with` and
accessing attributes needs to be done.

* * *

**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)
