Rails first_or_create vs find_or_create_by on ActiveRecord

Rails ActiveRecord provides methods like first_or_create, find_or_create_by methods to insert data based on certain conditions or create new records. We need to understand difference between first_or_create and find_or_create_by to use them as per need.

First things first, first_or_create is not available in Public API anymore. Documentation for Find or Build a New Object on Rails documentation does not enlist method(s) first_or_create and first_or_create! methods anymore. They were listed in documentation previously. Since, it was available in public documentation previously and people started using it in their repositories, it has created some confusion with newly available methods such as find_or_create_by and find_or_create_by! to perform similar functionality.

first_or_create

Listing down some code using first_or_create below.

project = Project.first_or_create(name: 'Ruby on Rails', status: 'active')

What do you expect to happen if the code is run?

  • Return first record or create a user with name as John Doe and email as [email protected]

Well, the first part of the sentence above,

Return first record

This means, it will return any first record from the table Project. It does not use the conditions passed to query and find the record to return if exists.

This causes confusion as we pass arguments to first_or_create which are name equals Ruby on Rails and status equals active, we may end up assuming that first_or_create will find a record that satisfies this condition and return it otherwise it will create a new record with given conditions.

That’s why, Rails has added find_or_create_by variant and make available in public API.

So, when first_or_create is useful?

We can use first_or_create without where clause, if we just want to make sure some record exists in the target table.

We can also use first_or_create coupled with where clause to get the desired result as given below.

project = Project.where(name: 'Ruby on Rails', status: 'active').first_or_create

Now, this will first search for a Project with given conditions in where clause, if the record exists, it will be returned. Otherwise, it will create record with those conditions.

find_or_create_by

Find or create by method on ActiveRecord relation makes it explicitely clear that,

  • it will find records with given where conditions, return record it exists
  • otherwise it will create a new record with given conditions
project = Project.find_or_create_by(name: 'Ruby on Rails', status: 'active').first_or_create

This is exactly same as the query with first_or_create along with where clause explained above.

project = Project.where(name: 'Ruby on Rails', status: 'active').first_or_create

Conclusion

It is important to understand subtle differences between methods first_or_create and find_or_create_by methods on ActiveRecord in Rails to effectively use them as per the need.