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.