I\'m looking for a clean way to create a record with a set of attributes if the record does not exist and - if the record do exist - to update its attributes. I love the syn
I have coded this finders that can be used for different scenarios.
The most important thing is, that it removes the parameter :id
on create and update.
Creating a model with :id
can cause problems with MySql
or PostgreSQL
because Rails uses the auto sequence number of the database. If you create new model instances with an :id
you can get a UniqueViolation: ERROR: duplicate key value violates unique constraint
.
# config/initializers/model_finders.rb
class ActiveRecord::Base
def self.find_by_or_create(attributes, &block)
self.find_by(attributes) || self.create(attributes.except(:id), &block)
end
def self.find_by_or_create!(attributes, &block)
self.find_by(attributes) || self.create!(attributes.except(:id), &block)
end
def self.find_or_create_update_by(attributes, &block)
self.find_by(attributes).try(:update, attributes.except(:id), &block) || self.create(attributes.except(:id), &block)
end
def self.find_or_create_update_by!(attributes, &block)
self.find_by(attributes).try(:update!, attributes.except(:id), &block) || self.create!(attributes.except(:id), &block)
end
def self.find_by_or_initialize(attributes, &block)
self.find_by(attributes) || new(attributes.except(:id), &block)
end
end