Create record if it does not exist in ActiveRecord
When writing a rails application you might want to create a record with parameters only if it doesn’t exist yet and if it does use that one.
A naive implementation may look similar to the following code.
if User.exists?(first_name: "John", last_name: "Smith") User.find(first_name: "John", last_name: "Smith") else User.create!(first_name: "John", last_name: "Smith") end
That is very tedious and it also adds a little bit performance overhead along the way. Fortunately, rails provides you with two nice methods for exactly this use case.
User.find_or_create_by(first_name: "John", last_name: "Smith") User.where(first_name: "John", last_name: "Smith").first_or_create
Both of them accepts a block where you can more custom code and initialization. Keep in mind that the block gets executed only when the record is created.
User.where(last_name: "Smith").first_or_create do |user| user.first_name = "John" end User.find_or_create_by(last_name: "Smith") do |user| user.first_name = "John" end
There are also bang equivalents
first_or_create_by! which raise an exception if the validation fails during the record creation.
The difference between the two of them is that
find_or_create_by is accepting a hash of attributes and uses them to perform the search and creation.
def find_or_create_by(attributes, &block) find_by(attributes) || create(attributes, &block) end
On the other hand, the
first_or_create uses attributes only for the creation and it returns the first record from provided scope.
def first_or_create(attributes = nil, &block) # :nodoc: first || create(attributes, &block) end
Therefore is more useful in combination with various scopes and where clauses where the parameters from the where clause are passed to the creation.
Would you like to get top 5 links on Programming every Monday?
Sign up to Programming Digest and stay up to date!