Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Allow delayed evaluation of attributes
The problem ------------ People often run into this problem: they want a different email per account, but they do this: ```elixir build_pair(:account, email: build(:email)) ``` The problem is that `build/2` is just a function call. So the above is equivalent to this: ```elixir email = build(:email) build_pair(:account, email: email) # same email ``` In other words, we get the same email factory for all of the accounts. That's especially confusing if we're using a `sequence` in the `email` factory. The problem is made worse when using it with Ecto. We can imagine the following scenario: ```elixir insert_pair(:account, user: build(:user)) ``` If the user factory has a uniqueness constraint, `insert_pair/2` will raise an error because we'll try to insert a user with the same value (even if using a sequence). Solution -------- The solution is to delay evaluation of the attributes. We do this allowing attributes to be functions. The trick then lies in the `build/2` function. We make it a terminal function in that it will evaluate any lazy attributes recursively. To do that, we update the `build/2` function to evaluate function attributes after merging any passed-in attributes. Previous implementations tried to solve the issue of delayed evaluation by introducing a `build_lazy/2` function. One of those was a simple alias to an anonymous function `fn -> build(:factory_name) end`. The other was a more complex approach that introduced a new private struct `%ExMachina.InstanceTemplate{}` to hold the data necessary to build the instance of that factory. We opt for the simpler approach because: - (a) it leaves room for flexibility in the future (we can add something like `build_lazy` alias if we want), and - (b) it opens the door for allowing the parent factory to be passed into the anonymous function in a factory definition: ```elixir def account_factory do %Account{ status: fn account -> build(:status, private: account.private) end } end ``` Not interacting with "full-control" factories --------------------------------------------- We opt for not evaluating lazy attributes in "full-control" factories. The whole point of allowing users to have full control of their factory attributes is for them to do with them what they will. We do expose a `evaluate_lazy_attributes/1` helper function, just like we expose a `merge_attributes/2` function so that users can emulate ExMachina's default behavior.
- Loading branch information
Showing
7 changed files
with
233 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
defmodule ExMachina.Publisher do | ||
use Ecto.Schema | ||
|
||
schema "users" do | ||
schema "publishers" do | ||
field(:pub_number, :string) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters