diff --git a/README.md b/README.md index 93310e2..5854e49 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ pairing with smart people at Hashrocket. For a steady stream of TILs, [sign up for my newsletter](https://tinyletter.com/jbranchaud). -_1138 TILs and counting..._ +_1139 TILs and counting..._ --- @@ -692,6 +692,7 @@ _1138 TILs and counting..._ - [Different Ways To Add A Foreign Key Reference](rails/different-ways-to-add-a-foreign-key-reference.md) - [Disambiguate Where In A Joined Relation](rails/disambiguate-where-in-a-joined-relation.md) - [Ensure Migrations Use The Latest Schema](rails/ensure-migrations-use-the-latest-schema.md) +- [Find Or Create A Record With FactoryBot](rails/find-or-create-a-record-with-factory-bot.md) - [Force All Users To Sign Out](rails/force-all-users-to-sign-out.md) - [Generating And Executing SQL](rails/generating-and-executing-sql.md) - [Get An Array Of Values From The Database](rails/get-an-array-of-values-from-the-database.md) diff --git a/rails/find-or-create-a-record-with-factory-bot.md b/rails/find-or-create-a-record-with-factory-bot.md new file mode 100644 index 0000000..9cc5094 --- /dev/null +++ b/rails/find-or-create-a-record-with-factory-bot.md @@ -0,0 +1,45 @@ +# Find Or Create A Record With FactoryBot + +I have a bunch of tests throughout my test suite that rely on a particular kind +of unique record. Let's say it is a special admin user. + +```ruby +admin = FactoryBot.create(:user, email: 'admin@company.com') +``` + +If this user has already been created then trying to re-create it with +[FactoryBot](https://github.com/thoughtbot/factory_bot) will result in a unique +email validation error. + +Another way to approach this would be to either find or create the admin user. +In some standard Rails code that might look like this: + +```ruby +admin = + User.find_by(email: 'admin@company.com') || + FactoryBot.create(:user, email: 'admin@company.com') +``` + +There is some repetitiveness to this that I'd like to avoid. FactoryBot doesn't +have an equivalent to ActiveRecord's `find_and_create_by`, but we can work +around this. + +We can add an `initialize_with` directive to the `User` factory. + +```ruby +FactoryBot.define do + factory :user do + sequence(:email) { |n| 'user#{n}@example.com' } + + # a bunch of other attributes + + initialize_with { User.find_or_create_by(email: email) } + end +end +``` + +With this in place, we can call `FactoryBot.create` with the already existing +_admin_ user and it will look up the record instead of raising a validation +error. + +[source](https://stackoverflow.com/a/11799674/535590)