I have library code that overrides Ar's find method. I also include the module for all Association classes so both MyModel.find and @parent.my_models.find work and apply the correct scope.
I based my code off of will_paginate's:
a = ActiveRecord::Associations
returning([ a::AssociationCollection ]) { |classes|
# detect http://dev.rubyonrails.org/changeset/9230
unless a::HasManyThroughAssociation.superclass == a::HasManyAssociation
classes << a::HasManyThroughAssociation
end
}.each do |klass|
klass.send :include, Finder::ClassMethods
klass.class_eval { alias_method_chain :method_missing, :paginate }
end
My problem is, I only want to override the finders for some models. Currently I need to extend all association collection classes which are shared by all models. I know I can extend associations per model by passing a module:
has_many :things, :extend => SomeCustomMethods
But my library is basically am ActiveRecord plugin, so I'd like a clean convention for plugable finder extensions that apply to both the model and scoped collections without affecting all models in the application.
Best Answer
You want to override
find_every
, which is the AR method that will ultimately runfind_by_sql
with the corresponding query. Overridingfind
won't work for customized finders, and it's just more fragile.But to be compatible with other plugins you can't just overload this method. Instead, alias it and call the original implementation after doing what you want:
This will enable your plugin for all classes. How do you want to control which models are enabled? Maybe a standard plugin accessor?
To support this you need to move the
class << base
to a class method (thusbase
should beself
). Like: