ActiveRecordPatchFirstOrCreate

Real atomic first_or_create/find_or_create_by for Rails

Installation

Add this line to your application's Gemfile:

gem 'active_record_patch_first_or_create'

And then execute:

$ bundle

Or install it yourself as:

$ gem install active_record_patch_first_or_create

Solution

We find out that methods like first_or_create or find_or_create_by are not atomic, you can check docs here

"Please note this method is not atomic, it runs first a SELECT, and if there are no results an INSERT is attempted. If there are other threads or processes there is a race condition between both calls and it could be the case that you end up with two similar records."

Usage

Finds the first record with the given attributes, or creates a record with the attributes if one is not found:

# Find the first user with uid "abc123" or create a new one.
User.where(uid: 'abc123').atomic_first_or_create(name: 'John', uid: 'abc123')
# => #<User id: 1, uid: "abc123", name: 'John'>
# Find the first user with uid "abc123" or create a new one.
# We already have one so the existing record will be returned.
User.where(uid: 'abc123').atomic_first_or_create(name: 'John', uid: 'abc123')
# => #<User id: 1, uid: "abc123", name: 'John'>
# Find the first user with uid "abc1234" or create a new one
User.where(uid: 'abc123').atomic_first_or_create(name: 'Johansson', uid: 'abc1234')
# => #<User id: 2, uid: "abc1234", name: 'Johansson'>