find_or_create_by
![Wide documentation Importance_3](https://d2vfyqvduarcvs.cloudfront.net/images/importance_3.png?1349367920)
- 1.0.0
- 1.1.6
- 1.2.6
- 2.0.3
- 2.1.0
- 2.2.1
- 2.3.8
- 3.0.0
- 3.0.9
- 3.1.0
- 3.2.1
- 3.2.8
- 3.2.13
- 4.0.2 (0)
- 4.1.8 (0)
- 4.2.1 (0)
- 4.2.7 (0)
- 4.2.9 (0)
- 5.0.0.1 (8)
- 5.1.7 (0)
- 5.2.3 (0)
- 6.0.0 (-38)
- 6.1.3.1 (0)
- 6.1.7.7 (0)
- 7.0.0 (0)
- 7.1.3.2 (29)
- 7.1.3.4 (0)
- What's this?
find_or_create_by(attributes, &block)
public
Finds the first record with the given attributes, or creates a record with the attributes if one is not found:
# Find the first user named "Penélope" or create a new one. User.find_or_create_by(first_name: 'Penélope') # => #<User id: 1, first_name: "Penélope", last_name: nil> # Find the first user named "Penélope" or create a new one. # We already have one so the existing record will be returned. User.find_or_create_by(first_name: 'Penélope') # => #<User id: 1, first_name: "Penélope", last_name: nil> # Find the first user named "Scarlett" or create a new one with # a particular last name. User.create_with(last_name: 'Johansson').find_or_create_by(first_name: 'Scarlett') # => #<User id: 2, first_name: "Scarlett", last_name: "Johansson">
This method accepts a block, which is passed down to create. The last example above can be alternatively written this way:
# Find the first user named "Scarlett" or create a new one with a # different last name. User.find_or_create_by(first_name: 'Scarlett') do |user| user.last_name = 'Johansson' end # => #<User id: 2, first_name: "Scarlett", last_name: "Johansson">
This method always returns a record, but if creation was attempted and failed due to validation errors it won’t be persisted, you get what create returns in such situation.
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.
Whether that is a problem or not depends on the logic of the application, but in the particular case in which rows have a UNIQUE constraint an exception may be raised, just retry:
begin CreditAccount.find_or_create_by(user_id: user.id) rescue ActiveRecord::RecordNotUnique retry end
![Default_avatar_30](https://www.gravatar.com/avatar/8ef46c3f25b9d06d1d903ec322fb4053?default=http://apidock.com/images/default_avatar_30.png&size=30)
Use :where or any defined scope before :find_or_create_by
You can chain find_or_create_by with :where, or any custom scope.
E.g.:
User.where(girls: true).find_or_create_by(first_name: ‘Scarlett’)
scope :celebrities, -> { where(celebrity: true) }
User.celebrities.create_with(last_name: ‘Johansson’).find_or_create_by(first_name: ‘Scarlett’)
![Default_avatar_30](https://www.gravatar.com/avatar/8d59c978430a1254eca78336f0272a61?default=http://apidock.com/images/default_avatar_30.png&size=30)
Are those supported versions correct?
It seems like this method was supported in versions prior to 4.0.2.
UPDATE never mind, wish I could delete this comment..