In order to reduce redundancy in my app, I have added the method
self.find_or_keep(object) to many of my models in order to find existing records with the same values, so I can reference the already existing ones instead of creating new records. Basically, this method checks most attributes for equality between two objects;
updated_at are always excluded for obvious reasons.
class IPv4 < ActiveRecord::Base # returns its param or an already existing record def self.find_or_keep(ipv4) # create new object in memory, if param is a Hash ipv4 = IPv4.new(ipv4) if ipv4.is_a?(Hash) return (entry = IPv4.find_by(address: ipv4.address, subnetmask: ipv4.subnetmask)) ? entry : ipv4 end end class Service < ActiveRecord::Base # returns its param or an already existing record def self.find_or_keep(service) # create new object in memory, if param is a Hash service = Service.new(service) if service.is_a?(Hash) return (entry = Service.find_by(protocol: service.protocol, port_from: service.port_from, port_to: service.port_to)) ? entry : service end end
As you can see, it's not very DRY. The problem here is that the method each time has to check for different parameters, so I have to rewrite the
find_by every time I want to use the method in another class. What I have in mind for DRYing it up is something like this:
class IPv4 < ActiveRecord::Base implement_find_or_keep_with(:address, :subnetmask) end class Service < ActiveRecord::Base implement_find_or_keep_with(:protocol, :port_from, :port_to) end class ActiveRecord::Base # whatever is need end
Is something like this possible? If so, how would I implement it?