---
title: Deprecating static attributes in factory_bot 4.11
teaser: 'Static attributes have been the source of much confusion over the years.
  Their deprecation will come with a rubocop-rspec Cop to automatically replace with
  dynamic attributes.

  '
tags: factory_bot,open source,testing,ruby
author: Daniel Colson
published_on: 2018-08-16
---

[factory\_bot][fb] has traditionally allowed you to define attributes
dynamically, with a block:

```ruby
factory :robot do
  name { "Ralph" }
end
```

or statically:

```ruby
factory :robot do
  name "Ralph"
end
```

With the dynamic version, every time you build a new robot you will get a new
"Ralph" string for the name, whereas in the static version you will always get
the same string (i.e. the same object in memory).

Static attributes have been a source of much confusion over the years.
A large number of our GitHub issues and Stack Overflow questions have been
related to this confusion, and we have been thinking about deprecating static
attributes [since 2013][static-deprecation-issue].

Getting the same string for every robot name is not great,
since mutating it will affect other robots:

```ruby
factory :robot do
  name "Ralph"
end

robot1 = build(:robot)
robot2 = build(:robot)

robot2.name
#=> "Ralph"

robot1.name << "y"

robot2.name
#=> "Ralphy"
```

This can lead to confusing, order-dependent bugs in your test suite.

Using methods like `Time.now` with static attributes can also be confusing:

```ruby
factory :post do
  published_at Time.now
end

first_post = build(:post)

Timecop.travel(2.days.from_now)

second_post = build(:post)
```

You might expect those two posts to have different `published_at` times, but
instead every post you build will have the same time, based on when the factory
definition was loaded.

Using persisted records with static attributes can be confusing as well:

```ruby
factory :robot do
  friend Person.create!(name: "Daniel")
end
```

With this factory, every robot you build will be friends with the same Daniel.
That may be good for Daniel,
but it probably doesn't make sense for your test suite.

This example gets worse if you use [factory\_bot\_rails][fbr].
factory\_bot\_rails is normally included in the test and development groups of
your Gemfile (it needs to be in the development group if you use the generators,
and you may also use it to create records when messing around in the console).
Since factory\_bot\_rails automatically loads factory definitions as your
application loads, writing a definition like this would cause another Daniel
to get added to your database every time you start the server or open a console.
I like Daniels and all, but there is a limit.

With all this potential for confusion, it doesn't make sense for us to keep
static attributes around. We will deprecate them in factory\_bot 4.11,
and we will remove them entirely in factory\_bot 5.

While I think there was something visually satisfying about defining
attributes without a block, I like even better that I no longer need to think
about whether or not the block is necessary.

Deprecation warnings aren't exactly fun. To make life easier for factory\_bot
users, we added a [rubocop-rspec Cop][cop] to help. Hopefully upgrading will be
as simple as adding `rubocop-rspec` to your Gemfile and running:

```shell
rubocop \
  --require rubocop-rspec \
  --only FactoryBot/AttributeDefinedStatically \
  --auto-correct
```

I may write more about my adventures with RuboCop another day. In the
meantime, I wish you a painless upgrade!

[fb]: https://github.com/thoughtbot/factory_bot
[fbr]: https://github.com/thoughtbot/factory_bot_rails
[static-deprecation-issue]: https://github.com/thoughtbot/factory_bot/issues/592
[cop]: https://github.com/rubocop-hq/rubocop-rspec/pull/666

Visit our [Open Source page](https://thoughtbot.com/open-source) to learn more about our team's contributions.
