Skip to content

Commit

Permalink
Document integration with 2.7 and 3.0 syntactic sugars
Browse files Browse the repository at this point in the history
Ruby 2.7 introduced [numbered block parameters][], and 3.0 introduced
[Hash literal value omission][], so document how they integrate with
Factory Bot.

[numbered block parameters]: https://ruby-doc.org/core-2.7.1/Proc.html#class-Proc-label-Numbered+parameters
[Hash literal value omission]: https://docs.ruby-lang.org/en/3.1/syntax/literals_rdoc.html#label-Hash+Literals
  • Loading branch information
seanpdoyle committed Sep 1, 2023
1 parent 3585b46 commit d391321
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 4 deletions.
45 changes: 41 additions & 4 deletions GETTING_STARTED.md
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,9 @@ user = create(:user)
# Returns a hash of attributes that can be used to build a User instance
attrs = attributes_for(:user)

# Integrates with Ruby 3.0's support for pattern matching assignment
attributes_for(:user) => {email:, name:, **attrs}

# Returns an object with all defined attributes stubbed out
stub = build_stubbed(:user)

Expand All @@ -297,7 +300,7 @@ end
### Attribute overrides

No matter which strategy is used, it's possible to override the defined
attributes by passing a hash:
attributes by passing a Hash:

```ruby
# Build a User instance and override the first_name property
Expand All @@ -306,6 +309,29 @@ user.first_name
# => "Joe"
```

Overriding associations is also supported:

```ruby
account = build(:account, :deluxe)
friends = build_list(:user, 2)

user = build(:user, account: account, friends: friends)
```

Ruby 3.1's support for [omitting values][] from `Hash` literals dovetails
attribute overrides and provides an opportunity to limit the repetition of
variable names:

```ruby
account = build(:account, :deluxe)
friends = build_list(:user, 2)

# The keyword arguments correspond to local variable names, so omit their values
user = build(:user, account:, friends:)
```

[omitting values]: https://docs.ruby-lang.org/en/3.1/syntax/literals_rdoc.html#label-Hash+Literals

### `build_stubbed` and `Marshal.dump`

Note that objects created with `build_stubbed` cannot be serialized with
Expand Down Expand Up @@ -945,7 +971,7 @@ end
Note that this approach works with `build`, `build_stubbed`, and `create`, but
the associations will return `nil` when using `attributes_for`.

Also, note that if you assign any attributes inside a custom `initialize_with`
Also, note that if you assign any attributes inside a custom `initialize_with`
(e.g. `initialize_with { new(**attributes) }`), those attributes should not refer to `instance`,
since it will be `nil`.

Expand Down Expand Up @@ -1008,6 +1034,17 @@ factory :user do
end
```

With Ruby 2.7's support for [numbered parameters][], inline definitions can be
even more abbreviated:

```ruby
factory :user do
sequence(:email) { "person#{_1}@example.com" }
end
```

[numbered parameters]: https://ruby-doc.org/core-2.7.1/Proc.html#class-Proc-label-Numbered+parameters

### Initial value

You can override the initial value. Any value that responds to the `#next`
Expand Down Expand Up @@ -1222,11 +1259,11 @@ FactoryBot.define do
created_at { 8.days.ago }
updated_at { 4.days.ago }
end

factory :user, traits: [:timestamps] do
username { "john_doe" }
end

factory :post do
timestamps
title { "Traits rock" }
Expand Down
22 changes: 22 additions & 0 deletions spec/acceptance/attributes_for_destructuring.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
describe "Ruby 3.0: attributes_for destructuring syntax" do
include FactoryBot::Syntax::Methods

before do
define_model("User", name: :string)

FactoryBot.define do
factory :user do
sequence(:email) { "email_#{_1}@example.com" }
name { "John Doe" }
end
end
end

it "supports being destructured" do
attributes_for(:user) => {name:, **attributes}

expect(name).to eq("John Doe")
expect(attributes.keys).to eq([:email])
expect(attributes.fetch(:email)).to match(/email_\d+@example.com/)
end
end
4 changes: 4 additions & 0 deletions spec/acceptance/attributes_for_spec.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
if RUBY_VERSION >= "3.0"
require_relative "./attributes_for_destructuring"
end

describe "a generated attributes hash" do
include FactoryBot::Syntax::Methods

Expand Down

0 comments on commit d391321

Please sign in to comment.