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