What is the cleanest way to override ActiveRecord for both models and collections?

I have a library code that overrides the Ar search method. I also include a module for all Association classes, so I work both MyModel.find and @ parent.my_models.find and apply the correct scope.

I based my code on the will_paginate file:

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 that I only want to override the crawlers for some models. Currently, I need to extend all association collection classes that are used by all models. I know that I can expand the associations for each model by passing a module:

has_many :things, :extend => SomeCustomMethods

ActiveRecord, , , , .

+3
3

find_every, AR-, find_by_sql . find , .

. , :

module MyPlugin
  def self.included(base)
    class << base
      alias_method :find_every_without_my_plugin, :find_every
      def find_every(*args)
        # do whatever you need ...
        find_every_without_my_plugin(*args)
      end
    end
  end
end

ActiveRecord::Base.send :include, MyPlugin

. , ? , ?

class User < ActiveRecord::Base
  my_plugin
end

, class << base ( base self). :

module MyPlugin
  def self.included(base)
    class << base
      base.extend ClassMethods
    end
  end

  module ClassMethods
    def my_plugin
      class << self
        alias_method :find_every_without_my_plugin, :find_every
        # ...
      end
    end
  end
end
+7

, , Ruby , .

ActiveRecord:

def self.find(*args)
  super
end

, . . , , , .

, .

+5

“Pedro's answer is right, but there is a small mistake.

def self.included(base)
  class << base
    base.extend ClassMethods
  end
end

it should be

def self.included(base)
  base.extend ClassMethods
end

Using the class <base ... end has the effect of calling 'extend' to 'base' in the class area, but there is no 'base' method in ActiveRecord :: Base, so an error occurs. Using base.extend will itself invoke the extend method of ActiveRecord :: Base.

0
source

All Articles