3

Ar の find メソッドをオーバーライドするライブラリ コードがあります。MyModel.find と @parent.my_models.find の両方が機能し、正しいスコープが適用されるように、すべての Association クラスのモジュールも含めます。

私のコードは will_paginate のものに基づいています:

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

私の問題は、一部のモデルのファインダーのみをオーバーライドしたいということです。現在、すべてのモデルで共有されているすべての関連コレクション クラスを拡張する必要があります。モジュールを渡すことで、モデルごとに関連付けを拡張できることはわかっています。

has_many :things, :extend => SomeCustomMethods

しかし、私のライブラリは基本的に ActiveRecord プラグインなので、アプリケーション内のすべてのモデルに影響を与えることなく、モデルとスコープ コレクションの両方に適用される、プラグ可能なファインダー拡張機能の明確な規則が必要です。

4

3 に答える 3

10

対応するクエリで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
于 2008-11-25T05:03:59.377 に答える
6

まず、Rubyのメソッド呼び出しの継承構造をよく知っていることを確認してください。これがないと、暗闇の中で刺されてしまう可能性があります。

ActiveRecordクラス内でこれを行う最も簡単な方法は次のとおりです。

def self.find(*args)
  super
end

アソシエーションはベースファインダー自体を使用するため、これはアソシエーションにも当てはまります。今、あなたはあなたのカスタマイズをする必要があります。その複雑さは大きく異なる可能性があり、あなたが何をしているのかわからないので、推奨事項を提供することはできません。

また、これを動的に定義すること自体が演習になりますが、これにより正しい方向を示すことができます。

于 2008-11-24T19:05:31.473 に答える
0

「ペドロの答えは正しいが、小さな間違いがある。

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

する必要があります

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

class << base ... end を使用すると、クラス メソッド スコープの 'base' で 'extend' を呼び出す効果がありますが、ActiveRecord::Base にはメソッド 'base' がないため、エラーがスローされます。base.extend を単独で使用すると、ActiveRecord::Base の「extend」メソッドが呼び出されます。

于 2010-01-15T01:31:02.307 に答える