Rails 6 has added ActiveRecord::Base.create_or_find_by/! as an alternative to ActiveRecord::Base.find_or_create_by/!

#### find_or_create_by

Relation#find_or_create_by is one of Rails finder methods, that finds the first record with the given attributes, or creates a record with the attributes if one is not found.

One of the problems of this approach is that its not an atomic operation. It first runs a SELECT, and if there are no results an INSERT is attempted.

In high scale applications, this can cause race conditions due to stale reads. Separate threads might attempt to first SELECT and then end up INSERT ing multiple records.

#### Overcoming duplicate inserts

One way of still overcoming this race condition is catching duplicate record errors. These errors are thrown only if there is an underlying unique constraint on a field.

In above scenario, it attempts an insert, if a race condition is hit, an ActiveRecord::RecordNotUnique is thrown. We can simply rescue and retry again, to fetch the existing record.

#### create_or_find_by

Enter create_or_find_by.

create_or_find_by tries to create a new record with the given attributes,
that has a unique constraint on one or several of its columns.

As in our example above, if a record already exists with one of these unique constraints, an exception raised is first caught.

It then proceeds to use find_by! and returns the record.

This helps use to overcome the stale reads issue which is caused by race conditions.

#### Limitations

create_or_find_by does have its own limitations even though it overcomes stale reads issue.

We can still be hit by a race condition of INSERT -> DELETE -> SELECT, which will end up with no result found. This is a much rarer scenario than the SELECT -> INSERT situation.

This only works if we have unique constraints on all columns we are using to create or find by. If we don’t, it will not raise ActiveRecord::RecordNotUnique, and simply insert a duplicate record.

Since all this mechanism relies on throwing and catching exceptions, it can tend to be relatively slower.