wholemeal

Chunky | Goodness

Find_or_create - Did You Find, or Create?

find_or_create_by_* is a great utility in the Rails toolbox. It allows you search for an object in the database by an arbitrary field, and if a matching object is not found, a new one is created.

# If a user with the given email address is present in the database, it is
# fetched and returned.  Otherwise, a new one is created and saved.
@user = User.find_or_create_by_email('user@example.com')

However, there does not appear to be a way to find out whether the object was found, or whether a new one was created.

One solution is to use the related find_or_initialize_by_* method, which is identical, except that is a matching record is found, a new object is returned

@user = User.find_or_initialize_by_email("user@example.com")
if @user.new_record?
  # Do whatevahs ...
end

Here’s my solution to doing it with find_or_create. It makes use of the fact that an optional block can be passed to find_or_create_by, which is only executed when a matching record is not found.

class User < ActiveRecord::Base
  # A flag to store whether the record was created by find_or_create_by_*
  attr_accessor :was_created
end

@user = User.find_or_create_by_email('user@example.com') do |u|
  u.was_created = true
end

if @user.was_created
  # Do whatevahs
end

I’d be interested in alternative approaches.

Comments