I have a Sinatra application using ActiveRecord and I wish to add a feature where I can generate a fingerprint (SHA1) for a set of records.
The way I’ve implemented this is by defining a module and including it within ActiveRecord::Relation as follows:
module Fingerprints
def sha1
Digest::SHA1.hexdigest map{ |record| record.attributes.values.join }.join
end
end
ActiveRecord::Relation.send :include, Fingerprints
I can now call ‘sha1’ on a ActiveRecord::Relation and get the value I need.
My question is whether this is the “preferred” way to be doing this (extending ActiveRecord with additional functionality)?
The final line that uses send feels unclean to me and the simple fact that I’m bolting features onto a class that isn’t my own also feels like a hack. I know this is a standard pattern in Ruby but reaching into ActiveRecords guts and patching it in this way is unfamiliar to me.
The alternative is to create a Sinatra helper that takes a ActiveRecord::Relation and returns the fingerprint. While this feels cleaner, I can’t help feeling that the sha1 method should really belong to the ActiveRecord::Relation class to better describe it’s intent.
This might be simply down to personal preference but I’d be interested how others do this and whether there is a feeling of the “right” way this is done.
Thanks
In all honesty I can’t see any real problem with what you’ve done. Perhaps call the method
fingerprint_shato prevent clobbering, maybe add an custom exception so that if any problems occur you know that it started in your code and not AR’s.Personally, I’d probably have made this a helper and passed in the relation, it could well be more obvious where the method was defined for others if it’s in the helpers, but like I say I don’t see a problem with what you’ve done and think it’s a good solution.
Maybe someone else will come along and say different and we’ll both learn something here 🙂