Rails has a dynamic method where you can do find_or_create_by_attr_name(attr) but it the method names get incredibly long very quickly. So SJS wrote "this article":http://sami.samhuri.net/2007/4/11/activerecord-base-find_or_create-and-find_or_initialize in which he tries to remedy the situation. His solution was pretty elegant but it still only worked for fields that were already defined in the database; if you often redefine setter methods it doesn't work at all.
Here's my attempt to remedy the situation.
module ActiveRecordExtensions
def self.included(base)
base.extend(ClassMethods)
end
module ClassMethods
def find_or_create(params)
begin
return self.find(params[:id])
rescue ActiveRecord::RecordNotFound => e
attrs = {}
# search for valid attributes in params
self.column_names.map(&:to_sym).each do |attrib|
# skip unknown columns, and the id field
next if params[attrib].nil? || attrib == :id
attrs[attrib] = params[attrib]
end
# call the appropriate ActiveRecord finder method
found = self.send("find_by_#{attrs.keys.join('_and_')}", *attrs.values) if !attrs.empty?
if found && !found.nil?
return found
else
return self.create(params)
end
end
end
alias create_or_find find_or_create
end
end
ActiveRecord::Base.send(:include, ActiveRecordExtensions)